j'ai commencé en essayant de stocker des chaînes dans SQLite en utilisant python, et a reçu le message:SQLite, python, unicode, et les données non-utf
sqlite3.ProgrammingError: You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit bytestrings (like text_factory = str). It is highly recommended that you instead just switch your application to Unicode strings.
Ok, je suis passé à des chaînes Unicode. Puis j'ai commencé à recevoir le message:
sqlite3.OperationalError: Could not decode to UTF-8 column 'tag_artist' with text 'Sigur Rós'
lorsque vous essayez de récupérer des données à partir de la base de données. D'autres recherches ont commencé et j'encoder en UTF8, mais «Sigur Rós des départs à la recherche comme 'Sigur Rós de
Note: Ma console a été configuré pour afficher dans « LATIN_1 » comme @John Machin a souligné.
Ce qui donne? Après avoir lu this, décrivant exactement la même situation que je suis, il semble que le conseil est d'ignorer l'autre conseil et d'utiliser des octets 8 bits après tout. Je n'avais pas beaucoup de connaissances sur unicode et utf avant de commencer ce processus. J'ai appris pas mal de choses au cours des deux dernières heures, mais je ne sais toujours pas s'il existe un moyen de convertir correctement «ó» du latin-1 en utf-8 sans le modifier. Si ce n'est pas le cas, pourquoi sqlite 'recommande-t-il' de changer mon application en chaînes Unicode?
Je vais mettre à jour cette question avec un résumé et quelques exemples de code de tout ce que j'ai appris au cours des dernières 24 heures afin que quelqu'un dans mes chaussures peut avoir un outil facile (er) guide. Si les informations que je publie sont fausses ou trompeuses, dites-le moi et je les mettrai à jour, ou l'un de vos supérieurs pourra mettre à jour.
Résumé des réponses
Permettez-moi d'abord indiquer le but que je le comprends. Le but du traitement des différents encodages, si vous essayez de les convertir, est de comprendre le codage de votre source, puis de le convertir en unicode en utilisant ce codage source, puis de le convertir en votre encodage désiré. Unicode est une base et les encodages sont des mappages de sous-ensembles de cette base. utf_8 a de la place pour chaque personnage en unicode, mais comme ils ne sont pas au même endroit que, par exemple, latin_1, une chaîne encodée en utf_8 et envoyée à une console latin_1 ne ressemblera pas à ce que vous attendez. En python le processus d'obtention de unicode et dans un autre encodage ressemble à:
str.decode('source_encoding').encode('desired_encoding')
ou si la str est déjà en unicode
str.encode('desired_encoding')
Pour sqlite je ne voulais pas réellement encoder à nouveau, Je voulais le décoder et le laisser au format Unicode. Voici quatre choses dont vous devrez peut-être prendre conscience lorsque vous essayez de travailler avec unicode et des encodages en python.
- Le codage de la chaîne avec laquelle vous souhaitez travailler et le codage souhaité.
- Le codage du système.
- Codage de la console.
- L'encodage du fichier source
Elaboration:
(1) Lorsque vous lisez une chaîne à partir d'une source, il doit avoir un codage, comme LATIN_1 ou UTF_8. Dans mon cas, je reçois des chaînes de caractères, donc malheureusement, je pourrais obtenir n'importe quel type d'encodage. Windows XP utilise UCS-2 (un système Unicode) comme son type de chaîne natif, ce qui semble me tromper. Heureusement pour moi, les caractères dans la plupart des noms de fichiers ne seront pas composés de plus d'un type de codage source, et je pense que tous les miens étaient complètement latin_1, complètement utf_8, ou simplement ascii (qui est un sous-ensemble des deux ceux). Je les ai donc lus et décodés comme s'ils étaient encore dans latin_1 ou utf_8. Il est toutefois possible que vous ayez latin_1 et utf_8 et tous les autres caractères mélangés dans un nom de fichier sous Windows. Parfois, ces personnages peuvent apparaître comme des boîtes, d'autres fois ils ont l'air mutilés, et d'autres fois ils semblent corrects (caractères accentués et autres joyeusetés). Aller de l'avant
(2) Python a un encodage système par défaut qui est défini lorsque Python démarre et ne peut pas être modifié pendant l'exécution. Voir here pour plus de détails. Résumé sale ... et voici le fichier que j'ajouté:
\# sitecustomize.py
\# this file can be anywhere in your Python path,
\# but it usually goes in ${pythondir}/lib/site-packages/
import sys
sys.setdefaultencoding('utf_8')
Ce codage du système est celui qui obtient utilisé lorsque vous utilisez la fonction unicode (« str ») sans autres paramètres de codage. Pour le dire autrement, python essaie de décoder "str" en unicode en fonction du codage système par défaut.
(3) Si vous utilisez IDLE ou la ligne de commande python, je pense que votre console s'affichera en fonction du codage système par défaut. J'utilise pydev avec eclipse pour une raison quelconque, donc j'ai dû aller dans mes paramètres de projet, éditer les propriétés de configuration de lancement de mon script de test, aller à l'onglet Commun, et changer la console de latin-1 à utf-8 Je pouvais confirmer visuellement que je travaillais.
(4) Si vous voulez avoir des chaînes de test, par exemple
test_str = "ó"
dans votre code source, vous devrez dire python quel genre de vous coder utilisent dans ce fichier. (Pour votre information: quand je une erreur de frappe un codage je devais ctrl-Z parce que mon dossier est devenu illisible.) Ceci est facilement accompli en mettant une ligne comme tant en haut de votre fichier de code source:
# -*- coding: utf_8 -*-
Si vous ne « t ont cette information, les tentatives de python pour analyser votre code comme ascii par défaut, et ainsi:
SyntaxError: Non-ASCII character '\xf3' in file _redacted_ on line 81, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details
une fois que votre programme fonctionne correctement, ou, si vous ne l'utilisez la console de python ou de toute autre console pour regarder à la sortie, alors vous ne vous soucierez probablement que de # 1 sur la liste. La valeur par défaut du système et le codage de la console ne sont pas importants sauf si vous devez regarder la sortie et/ou si vous utilisez la fonction unicode() intégrée (sans aucun paramètre de codage) au lieu de la fonction string.decode(). J'ai écrit une fonction démo que je vais coller dans le fond de ce gâchis gigantesque qui, je l'espère, démontre correctement les éléments de ma liste. Voici une partie de la sortie lorsque je lance le caractère 'ó' à travers la fonction de démonstration, montrant comment différentes méthodes réagissent au caractère en entrée.Mon encodage du système et la sortie de la console sont tous deux sur UTF_8 pour cette course:
'�' = original char <type 'str'> repr(char)='\xf3'
'?' = unicode(char) ERROR: 'utf8' codec can't decode byte 0xf3 in position 0: unexpected end of data
'ó' = char.decode('latin_1') <type 'unicode'> repr(char.decode('latin_1'))=u'\xf3'
'?' = char.decode('utf_8') ERROR: 'utf8' codec can't decode byte 0xf3 in position 0: unexpected end of data
Maintenant, je vais changer le système et le codage de la console à LATIN_1, et je reçois cette sortie pour la même entrée:
'ó' = original char <type 'str'> repr(char)='\xf3'
'ó' = unicode(char) <type 'unicode'> repr(unicode(char))=u'\xf3'
'ó' = char.decode('latin_1') <type 'unicode'> repr(char.decode('latin_1'))=u'\xf3'
'?' = char.decode('utf_8') ERROR: 'utf8' codec can't decode byte 0xf3 in position 0: unexpected end of data
Notez que le caractère 'original' s'affiche correctement et que la fonction intégrée unicode() fonctionne maintenant.
Maintenant, je change la sortie de ma console en utf_8.
'�' = original char <type 'str'> repr(char)='\xf3'
'�' = unicode(char) <type 'unicode'> repr(unicode(char))=u'\xf3'
'�' = char.decode('latin_1') <type 'unicode'> repr(char.decode('latin_1'))=u'\xf3'
'?' = char.decode('utf_8') ERROR: 'utf8' codec can't decode byte 0xf3 in position 0: unexpected end of data
Ici, tout fonctionne toujours comme la dernière fois mais la console ne peut pas afficher la sortie correctement. Etc. La fonction ci-dessous affiche également plus d'informations que cela et, espérons-le, aiderait quelqu'un à comprendre où se situe l'écart dans leur compréhension. Je sais que toutes ces informations sont dans d'autres endroits et traitées de manière plus approfondie, mais j'espère que ce serait un bon point de départ pour quelqu'un qui essaie de coder avec python et/ou sqlite. Les idées sont géniales, mais parfois le code source peut vous sauver un jour ou deux d'essayer de comprendre quelles fonctions font quoi. Avertissements: Je ne suis pas un expert de l'encodage, je l'ai mis ensemble pour aider ma propre compréhension. Je continuais à construire dessus quand j'aurais probablement commencé à passer des fonctions comme arguments pour éviter autant de code redondant, donc si je peux, je vais le rendre plus concis. En outre, utf_8 et latin_1 ne sont en aucun cas les seuls systèmes d'encodage, ils sont juste les deux avec lesquels je jouais parce que je pense qu'ils gèrent tout ce dont j'ai besoin. Ajoutez vos propres schémas d'encodage à la fonction de démonstration et testez votre propre entrée.
Encore une chose: apparently crazy application developers rend la vie difficile sous Windows.
#!/usr/bin/env python
# -*- coding: utf_8 -*-
import os
import sys
def encodingDemo(str):
validStrings =()
try:
print "str =",str,"{0} repr(str) = {1}".format(type(str), repr(str))
validStrings += ((str,""),)
except UnicodeEncodeError as ude:
print "Couldn't print the str itself because the console is set to an encoding that doesn't understand some character in the string. See error:\n\t",
print ude
try:
x = unicode(str)
print "unicode(str) = ",x
validStrings+= ((x, " decoded into unicode by the default system encoding"),)
except UnicodeDecodeError as ude:
print "ERROR. unicode(str) couldn't decode the string because the system encoding is set to an encoding that doesn't understand some character in the string."
print "\tThe system encoding is set to {0}. See error:\n\t".format(sys.getdefaultencoding()),
print ude
except UnicodeEncodeError as uee:
print "ERROR. Couldn't print the unicode(str) because the console is set to an encoding that doesn't understand some character in the string. See error:\n\t",
print uee
try:
x = str.decode('latin_1')
print "str.decode('latin_1') =",x
validStrings+= ((x, " decoded with latin_1 into unicode"),)
try:
print "str.decode('latin_1').encode('utf_8') =",str.decode('latin_1').encode('utf_8')
validStrings+= ((x, " decoded with latin_1 into unicode and encoded into utf_8"),)
except UnicodeDecodeError as ude:
print "The string was decoded into unicode using the latin_1 encoding, but couldn't be encoded into utf_8. See error:\n\t",
print ude
except UnicodeDecodeError as ude:
print "Something didn't work, probably because the string wasn't latin_1 encoded. See error:\n\t",
print ude
except UnicodeEncodeError as uee:
print "ERROR. Couldn't print the str.decode('latin_1') because the console is set to an encoding that doesn't understand some character in the string. See error:\n\t",
print uee
try:
x = str.decode('utf_8')
print "str.decode('utf_8') =",x
validStrings+= ((x, " decoded with utf_8 into unicode"),)
try:
print "str.decode('utf_8').encode('latin_1') =",str.decode('utf_8').encode('latin_1')
except UnicodeDecodeError as ude:
print "str.decode('utf_8').encode('latin_1') didn't work. The string was decoded into unicode using the utf_8 encoding, but couldn't be encoded into latin_1. See error:\n\t",
validStrings+= ((x, " decoded with utf_8 into unicode and encoded into latin_1"),)
print ude
except UnicodeDecodeError as ude:
print "str.decode('utf_8') didn't work, probably because the string wasn't utf_8 encoded. See error:\n\t",
print ude
except UnicodeEncodeError as uee:
print "ERROR. Couldn't print the str.decode('utf_8') because the console is set to an encoding that doesn't understand some character in the string. See error:\n\t",uee
print
print "Printing information about each character in the original string."
for char in str:
try:
print "\t'" + char + "' = original char {0} repr(char)={1}".format(type(char), repr(char))
except UnicodeDecodeError as ude:
print "\t'?' = original char {0} repr(char)={1} ERROR PRINTING: {2}".format(type(char), repr(char), ude)
except UnicodeEncodeError as uee:
print "\t'?' = original char {0} repr(char)={1} ERROR PRINTING: {2}".format(type(char), repr(char), uee)
print uee
try:
x = unicode(char)
print "\t'" + x + "' = unicode(char) {1} repr(unicode(char))={2}".format(x, type(x), repr(x))
except UnicodeDecodeError as ude:
print "\t'?' = unicode(char) ERROR: {0}".format(ude)
except UnicodeEncodeError as uee:
print "\t'?' = unicode(char) {0} repr(char)={1} ERROR PRINTING: {2}".format(type(x), repr(x), uee)
try:
x = char.decode('latin_1')
print "\t'" + x + "' = char.decode('latin_1') {1} repr(char.decode('latin_1'))={2}".format(x, type(x), repr(x))
except UnicodeDecodeError as ude:
print "\t'?' = char.decode('latin_1') ERROR: {0}".format(ude)
except UnicodeEncodeError as uee:
print "\t'?' = char.decode('latin_1') {0} repr(char)={1} ERROR PRINTING: {2}".format(type(x), repr(x), uee)
try:
x = char.decode('utf_8')
print "\t'" + x + "' = char.decode('utf_8') {1} repr(char.decode('utf_8'))={2}".format(x, type(x), repr(x))
except UnicodeDecodeError as ude:
print "\t'?' = char.decode('utf_8') ERROR: {0}".format(ude)
except UnicodeEncodeError as uee:
print "\t'?' = char.decode('utf_8') {0} repr(char)={1} ERROR PRINTING: {2}".format(type(x), repr(x), uee)
print
x = 'ó'
encodingDemo(x)
Merci beaucoup pour les réponses ci-dessous et surtout à John Machin pour répondre si complètement.
J'ai eu ma configuration de terminal pour latin1, donc je changé. Quand vous demandez ce que j'appelle les chaînes Unicode, j'utilisais la méthode unicode() sur le str que je lisais. Je ne comprenais pas que les caractères Unicode contenaient encore un encodage implicite. Est-ce que je dis ça? Il me semble comme unicode ("\ xF3") et "\ xF3" .decode ('latin1') sont les mêmes lorsqu'il est évalué avec repr(). Est-ce une circonstance heureuse ou est-ce qu'unicode ("str") va toujours retourner le décodage correct? Si ce n'est pas le cas, quand je reçois une chaîne python contenant un jeu de caractères, comment savoir comment le décoder? –
Merci encore. Je suppose que la réponse à votre question "Qu'est-ce que vous appelez les chaînes Unicode? UTF-16?" est "quel que soit oacute_unicode". Est-ce que je manque un aspect de votre question que je devrais comprendre? J'ai décodé les chaînes que j'ai eues des noms de fichiers et les ai envoyées à la base de données sous cette forme. J'ai aussi commandé dix tambourins du Pentagone si je devais avoir des capacités de décodage militaire et que python serait inutile. –
Je vérifiais juste que vous vouliez vraiment dire des objets unicode Python == ce que oacute_unicode est, pas UTF-16 qui est une autre possibité de codage dans les bases de données SQLite et que certains appellent "Unicode". –