2010-03-06 7 views
64

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.

  1. Le codage de la chaîne avec laquelle vous souhaitez travailler et le codage souhaité.
  2. Le codage du système.
  3. Codage de la console.
  4. 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.

Répondre

34

I'm still ignorant of whether there is a way to correctly convert 'ó' from latin-1 to utf-8 and not mangle it

repr() et unicodedata.name() sont vos amis quand il s'agit de débogage de tels problèmes:

>>> oacute_latin1 = "\xF3" 
>>> oacute_unicode = oacute_latin1.decode('latin1') 
>>> oacute_utf8 = oacute_unicode.encode('utf8') 
>>> print repr(oacute_latin1) 
'\xf3' 
>>> print repr(oacute_unicode) 
u'\xf3' 
>>> import unicodedata 
>>> unicodedata.name(oacute_unicode) 
'LATIN SMALL LETTER O WITH ACUTE' 
>>> print repr(oacute_utf8) 
'\xc3\xb3' 
>>> 

Si vous envoyez oacute_utf8 à un terminal qui est mis en place pour latin1, vous obtiendrez un tilde suivi de 3-superscript.

I switched to Unicode strings.

Comment appelez-vous les chaînes Unicode? UTF-16?

What gives? After reading this, describing exactly the same situation I'm in, it seems as if the advice is to ignore the other advice and use 8-bit bytestrings after all.

Je ne peux pas imaginer comment il semble si vous. L'histoire qui était transmise était que les objets Unicode en Python et l'encodage UTF-8 dans la base de données étaient la voie à suivre. Cependant, Martin a répondu à la question initiale, en donnant une méthode ("text factory") pour que l'OP puisse utiliser latin1 - ceci ne constituait PAS une recommandation!

Mise à jour en réponse à ces autres questions soulevées dans un commentaire:

I didn't understand that the unicode characters still contained an implicit encoding. Am I saying that right?

No.Un encodage est un mappage entre Unicode et quelque chose d'autre, et vice versa. Un caractère Unicode n'a pas de codage, implicite ou autre.

It looks to me like unicode("\xF3") and "\xF3".decode('latin1') are the same when evaluated with repr().

Dites quoi? Il ne ressemble pas à moi:

>>> unicode("\xF3") 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xf3 in position 0: ordinal 
not in range(128) 
>>> "\xF3".decode('latin1') 
u'\xf3' 
>>> 

Peut-être que vous vouliez dire: u'\xf3' == '\xF3'.decode('latin1') ... cela est certainement vrai.

Il est également vrai que unicode(str_object, encoding) fait la même chose que str_object.decode(encoding) ... y compris le gonflement lorsqu'un codage inapproprié est fourni.

Is that a happy circumstance

Que les 256 premiers caractères Unicode sont les mêmes, le code pour le code, les 256 caractères latin1 est une bonne idée. Étant donné que les 256 caractères latin1 possibles sont mappés à Unicode, cela signifie que n'importe quel octet de 8 bits, tout objet STR Python peut être décodé en unicode sans qu'une exception soit levée. C'est comme ça devrait être.

Cependant, il existe certaines personnes qui confondent deux concepts bien distincts: "mon script se termine sans aucune exception" et "mon script est sans erreur". Pour eux, latin1 est "un piège et une illusion". En d'autres termes, si vous avez un fichier encodé en cp1252 ou gbk ou koi8-u ou quoi que ce soit et que vous le décodiez en utilisant latin1, l'Unicode qui en résultera sera complètement vide et Python (ou tout autre langage) ne sera pas signaler une erreur - il n'a aucun moyen de savoir que vous avez commis une bêtise.

or is unicode("str") going to always return the correct decoding?

Juste comme ça, avec l'encodage par défaut étant ascii, il retournera le unicode correct si le fichier est en fait codé en ASCII. Sinon, ça va exploser.

De même, si vous spécifiez le codage correct ou un sur-ensemble du codage correct, vous obtiendrez le résultat correct. Sinon, vous aurez du charabia ou une exception.

En résumé: la réponse est non.

If not, when I receive a python str that has any possible character set in it, how do I know how to decode it?

Si l'objet STR est un document XML valide, il sera spécifié au premier plan. La valeur par défaut est UTF-8. S'il s'agit d'une page Web correctement construite, elle doit être spécifiée à l'avance (cherchez "charset"). Malheureusement, de nombreux auteurs de pages Web mentent à travers leurs dents (ISO-8859-1 alias latin1, devrait être Windows-1252 alias cp1252, ne gaspillez pas de ressources en essayant de décoder gb2312, utilisez plutôt gbk). Vous pouvez obtenir des indices de la nationalité/langue du site.

UTF-8 vaut toujours la peine d'être essayé. Si les données sont ascii, cela fonctionnera bien, car ascii est un sous-ensemble de utf8. Une chaîne de texte qui a été écrite en utilisant des caractères non-ascii et qui a été encodée dans un encodage autre que utf8 échouera presque certainement avec une exception si vous essayez de le décoder comme utf8.

Toutes les heuristiques ci-dessus et plus et beaucoup de statistiques sont encapsulées dans chardet, un module pour deviner le codage de fichiers arbitraires. Cela fonctionne généralement bien. Cependant, vous ne pouvez pas rendre le logiciel idiot. Par exemple, si vous concaténez des fichiers de données écrits avec l'encodage A et d'autres avec l'encodage B, et que vous alimentez le résultat en chardet, la réponse est susceptible d'encoder C avec un niveau de confiance réduit, par ex. 0.8. Toujours vérifier la partie de confiance de la réponse.

Si tout le reste échoue:

(1) Essayez de demander ici, avec un petit échantillon de l'avant de vos données ... print repr(your_data[:400]) ... et quelles que soient les informations de garantie quant à son origine que vous avez.

(2) La recherche russe récente dans techniques for recovering forgotten passwords semble être tout à fait applicable pour déduire des codages inconnus.

Update 2 BTW, est-il pas temps que vous avez ouvert une autre question -)

One more thing: there are apparently characters that Windows uses as Unicode for certain characters that aren't the correct Unicode for that character, so you may have to map those characters to the correct ones if you want to use them in other programs that are expecting those characters in the right spot.

Il est pas Windows qui est de le faire?; c'est un tas de développeurs d'applications fous. Vous pourriez avoir plus naturellement pas paraphrasé mais a cité le premier paragraphe de l'article effbot dont vous avez parlé:

Some applications add CP1252 (Windows, Western Europe) characters to documents marked up as ISO 8859-1 (Latin 1) or other encodings. These characters are not valid ISO-8859-1 characters, and may cause all sorts of problems in processing and display applications.

Contexte:

La gamme U + 0000 à U + 001F inclus est désigné dans Unicode " C0 Caractères de contrôle ". Ceux-ci existent aussi en ASCII et latin1, avec les mêmes significations. Ils incluent des choses familières telles que le retour chariot, le saut de ligne, la cloche, le retour arrière, la tabulation, et d'autres qui sont rarement utilisés.

La plage U + 0080 à U + 009F inclus est désignée en Unicode par "C1 Control Characters". Ceux-ci existent également dans latin1, et comprennent 32 caractères que personne en dehors de unicode.org ne peut imaginer pour une utilisation possible. Par conséquent, si vous exécutez un nombre de fréquence de caractères sur vos données unicode ou latin1 et que vous trouvez des caractères dans cette plage, vos données sont corrompues. Il n'y a pas de solution universelle. Cela dépend de comment il est devenu corrompu. Les caractères peuvent avoir la même signification que les caractères cp1252 aux mêmes positions, et ainsi la solution de l'effbot fonctionnera. Dans un autre cas que j'ai examiné récemment, les caractères douteux semblent avoir été causés par la concaténation de fichiers texte codés en UTF-8 et un autre encodage qui devait être déduit en fonction des fréquences de lettres dans le langage (humain) les fichiers étaient écrit en.

+0

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? –

+0

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. –

+0

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". –

7

Bien sûr qu'il y a. Mais vos données sont déjà cassé dans la base de données, vous aurez donc besoin de le corriger:

>>> print u'Sigur Rós'.encode('latin-1').decode('utf-8') 
Sigur Rós 
20

UTF-8 est le codage par défaut des bases de données SQLite. Cela apparaît dans des situations comme "SELECT CAST (x'52C3B373 'AS TEXT)". Cependant, la bibliothèque SQLite C ne vérifie pas si une chaîne insérée dans un DB est valide UTF-8.

Si vous insérez un objet Python unicode (ou un objet str dans 3.x), la bibliothèque Python sqlite3 le convertira automatiquement en UTF-8. Mais si vous insérez un objet str, il faudra juste supposer que la chaîne est UTF-8, car Python 2.x "str" ​​ne connaît pas son encodage. C'est une raison de préférer les chaînes Unicode.

Cependant, cela ne vous aide pas si vos données sont cassées pour commencer.

Pour corriger vos données, ne

db.create_function('FIXENCODING', 1, lambda s: str(s).decode('latin-1')) 
db.execute("UPDATE TheTable SET TextColumn=FIXENCODING(CAST(TextColumn AS BLOB))") 

pour chaque colonne de texte dans votre base de données.

+0

C'est vraiment utile. Je n'en ai pas besoin tout de suite parce que j'essaie juste de comprendre ce genre de choses et que mon db est jetable, mais cela mérite une mise à jour pour l'utilité. –

+0

J'ai écrit un petit script qui utilise cette technique pour ré-encoder toutes les colonnes 'text',' clob', et 'char', dans toutes les tables de la base de données cible. http://stackoverflow.com/a/29048500/1191425. –

18

Je résolu ce problème pysqlite en définissant:

conn.text_factory = lambda x: unicode(x, 'utf-8', 'ignore') 

Par text_factory par défaut est réglé sur unicode(), qui utilisera l'encodage par défaut actuel (ascii sur ma machine)

+0

Bien que 'text_factory' soit mentionné dans l'erreur que je reçois, je ne trouve aucune référence à cela dans SQL Alchemy v0.7.6 docs en ligne à http://docs.sqlalchemy.org/en/latest/ – RobM

+0

Je l'ai fait mais est toujours se plaindre. – fiatjaf

+0

Super! Juste un petit changement dans mon cas: Il s'agissait de supprimer des caractères avec un accent ... donc j'ai utilisé 'conn.text_factory = lambda x: x.decode ('latin-1')' – luc

2

Mes problèmes unicode avec 2.x Python (Python 2.7.6 pour être précis) fixé ceci:

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 

from __future__ import unicode_literals 
import sys 
reload(sys) 
sys.setdefaultencoding('utf-8') 

Il a également résolu l'erreur que vous évoquez à droite au début du poste:

sqlite3.ProgrammingError: You must not use 8-bit bytestrings unless ...

EDIT

sys.setdefaultencoding est un sale hack. Oui, cela peut résoudre les problèmes de l'UTF-8, mais tout a un prix. Pour plus de détails, consultez les liens suivants:

+1

N'utilisez pas 'sys.setdefaultencoding() '. C'est une culture de la cargaison terrible, et sert seulement à * cacher la rupture temporairement *. Ça va casser d'autres choses. Vous êtes juste en poudre sur les contusions plutôt que d'arrêter d'être frappé par des coups de poing. Arrêtez de vous faire poinçonner à la place et manipulez Unicode correctement. –