Utilisation des fonctions unicode () et encode () en Python

83

J'ai un problème avec le codage de la variable de chemin et son insertion dans la base de données SQLite . J'ai essayé de le résoudre avec la fonction d' encode ("utf-8") qui n'a pas aidé. Ensuite, j'ai utilisé la fonction unicode () qui me donne le type unicode .

print type(path)                  # <type 'unicode'>
path = path.replace("one", "two") # <type 'str'>
path = path.encode("utf-8")       # <type 'str'> strange
path = unicode(path)              # <type 'unicode'>

Enfin, j'ai gagné le type unicode , mais j'ai toujours la même erreur qui était présente lorsque le type de la variable de chemin était str

sqlite3.ProgrammingError: Vous ne devez pas utiliser de chaînes d'octets 8 bits, sauf si vous utilisez une text_factory qui peut interpréter des chaînes d'octets 8 bits (comme text_factory = str). Il est fortement recommandé de simplement basculer votre application vers des chaînes Unicode.

Pourriez-vous m'aider à résoudre cette erreur et expliquer l'utilisation correcte de encode("utf-8")et des unicode()fonctions? Je me bats souvent avec.

ÉDITER:

Cette instruction execute () a généré l'erreur:

cur.execute("update docs set path = :fullFilePath where path = :path", locals())

J'ai oublié de changer l'encodage de la variable fullFilePath qui souffre du même problème, mais je suis assez confus maintenant. Dois-je utiliser uniquement unicode () ou encoder ("utf-8") ou les deux?

Je ne peux pas utiliser

fullFilePath = unicode(fullFilePath.encode("utf-8"))

car cela soulève cette erreur:

UnicodeDecodeError: le codec 'ascii' ne peut pas décoder l'octet 0xc5 en position 32: ordinal pas dans la plage (128)

La version Python est 2.7.2

xralf
la source
où est le code qui soulève l'erreur?
newtover
2
Votre question exacte a déjà reçu une réponse: [ stackoverflow.com/questions/2392732/… [1]: stackoverflow.com/questions/2392732/…
garnertb
@newtover J'ai édité la question.
xralf
avez-vous converti les deux variables utilisées en unicode?
newtover
2
Apprendre comment Python 3 gère le texte et les données m'a vraiment aidé à tout comprendre. Il est alors facile d'appliquer les connaissances à Python 2.
Oleh Prypin

Réponses:

87

Vous n'utilisez encode("utf-8")pas correctement. Les chaînes d'octets Python ( strtype) ont un encodage, pas Unicode. Vous pouvez convertir une chaîne Unicode en chaîne d'octets Python à l'aide de uni.encode(encoding), et vous pouvez convertir une chaîne d'octets en chaîne Unicode en utilisant s.decode(encoding)(ou de manière équivalente, unicode(s, encoding)).

Si fullFilePathet pathsont actuellement un strtype, vous devez comprendre comment ils sont encodés. Par exemple, si l'encodage actuel est utf-8, vous utiliserez:

path = path.decode('utf-8')
fullFilePath = fullFilePath.decode('utf-8')

Si cela ne résout pas le problème, le problème réel peut être que vous n'utilisez pas de chaîne Unicode dans votre execute()appel, essayez de le modifier comme suit:

cur.execute(u"update docs set path = :fullFilePath where path = :path", locals())
Andrew Clark
la source
Cette déclaration fullFilePath = fullFilePath.decode("utf-8")soulève toujours une erreur UnicodeEncodeError: 'ascii' codec can't encode characters in position 32-34: ordinal not in range(128). fullFilePath est une combinaison de type str et string extraite de la colonne de texte de la table db qui doit être encodée en utf-8.
xralf
Selon cela, mais cela peut être UTF-8, UTF-16BE ou UTF-16LE. Puis-je le découvrir d'une manière ou d'une autre?
xralf
@xralf, Si vous combinez différents strobjets, vous pouvez mélanger des encodages. Pouvez-vous montrer le résultat de print repr(fullFilePath)?
Andrew Clark
Je ne peux le montrer qu'avant l'appel de decode () . Les caractères problématiques sont \ u0161 et \ u0165.
xralf
@xralf - Donc c'est déjà unicode? Essayez de changer l'appel d'exécution en unicode:cur.execute(u"update docs set path = :fullFilePath where path = :path", locals())
Andrew Clark
121

strest une représentation de texte en octets, unicodeest une représentation de texte en caractères.

Vous décodez du texte d'octets en unicode et encodez un unicode en octets avec un certain codage.

C'est:

>>> 'abc'.decode('utf-8')  # str to unicode
u'abc'
>>> u'abc'.encode('utf-8') # unicode to str
'abc' 
Newtover
la source
1
Très bonne réponse, droit au but. J'ajoute que unicodeparle des lettres ou des symboles, ou plus génériquement: runes tout strreprésente une chaîne d'octets dans un certain codage, que vous devez decode(évidemment dans le codage correct) pour obtenir les runes spécifiques
arainone
1

Assurez-vous d'avoir défini vos paramètres régionaux juste avant d'exécuter le script depuis le shell, par exemple

$ locale -a | grep "^en_.\+UTF-8"
en_GB.UTF-8
en_US.UTF-8
$ export LC_ALL=en_GB.UTF-8
$ export LANG=en_GB.UTF-8

Documents: man locale, man setlocale.

Kenorb
la source