2010-07-05 9 views
7

Je reviens d'une bibliothèque ce qui semble être une chaîne unicode incorrecte:Chaîne unicode Python avec UTF-8?

>>> title 
u'Sopet\xc3\xb3n' 

Maintenant, ces deux hex échappe, il y a l'encodage UTF-8 pour U + 00F3 LETTRE MINUSCULE LATINE O AIGU. Pour autant que je comprenne, une chaîne unicode en Python devrait avoir le caractère réel, pas le codage UTF-8 pour le personnage, donc je pense que c'est incorrect et vraisemblablement un bug soit dans la bibliothèque ou dans mon entrée, non? La question est, comment puis-je (a) reconnaître que j'ai le texte codé en UTF-8 dans ma chaîne unicode, et (b) convertir cela en une chaîne unicode appropriée?

Je suis perplexe sur (a), car il n'y a rien de mal, d'encodage, à propos de cette chaîne d'origine (c.-à-d., Les deux sont des caractères valides, u'\xc3\xb3' == ³, mais ils ne sont pas supposés être là)

On dirait que je peux obtenir (b) par eval() uant que la sortie repr() moins le devant « u » pour obtenir une str puis décoder la str avec UTF-8:

>>> eval(repr(title)[1:]).decode("utf-8") 
u'Sopet\xf3n' 
>>> print eval(repr(title)[1:]).decode("utf-8") 
Sopetón 

Mais cela semble un peu kludgy. Existe-t-il un moyen officiellement autorisé d'extraire les données brutes d'une chaîne unicode et de traiter cela comme une chaîne normale?

Répondre

10

a) Essayez de le passer à travers la méthode ci-dessous.

b)

>>> u'Sopet\xc3\xb3n'.encode('latin-1').decode('utf-8') 
u'Sopet\xf3n' 
+1

Note 1) il n'y a pas une manière générale de reconnaître utf-8; cela le reconnaîtra car le décodeur UTF-8 vérifiera que toutes les séquences de plusieurs octets qu'il a données sont valides, et lèvera une exception si ce n'est pas le cas, 2) l'astuce encode-to-Latin-1 fonctionne parce que vos points de code sont tous inférieurs à 256, et les points de code 0-255 d'Unicode correspondent exactement à la représentation de Latin-1. –

+0

Je ne suis pas sûr de comprendre complètement votre commentaire. Un contre-exemple spécifique pourrait peut-être aider. Pour autant que je comprenne, le ".encode ('latin-1')" est un no-op sauf que le résultat est un str plutôt qu'un unicode. Y at-il une chaîne pour laquelle ce ne sera pas le cas? Je suis d'accord qu'il n'y aura pas de manière générale de détecter UTF-8 à l'intérieur d'une chaîne unicode, car les octets codés UTF-8 auront une interprétation valide (si incorrecte) dans une chaîne unicode. Pour ma part, je ne suis vraiment intéressé que par Latin-1 (pour l'instant), donc c'est suffisant. – Watts

+0

@Watts: 'u' \ u03b5 \ u03bb \ u03bb \ u03b7 \ u03bd \ u03b9 \ u03ba \ u03ac signifie greek'.encode ('latin1') ' – tzot

8

Vous devez utiliser:

title.encode ('raw_unicode_escape')

python2:

print(u'\xd0\xbf\xd1\x80\xd0\xb8'.encode('raw_unicode_escape')) 

python3:

print(u'\xd0\xbf\xd1\x80\xd0\xb8'.encode('raw_unicode_escape').decode('utf8')) 
+2

vous avez sauvé ma journée. J'avais un objet unicode avec des octets utf-8 à l'intérieur, et je devais le décoder en unicode 'normal'. Cela m'a permis de le résoudre: 'my_str.encode ('raw_unicode_escape'). Decode ('utf-8')'.Je pense que c'est une solution plus générale que la réponse acceptée, car il décode les chaînes non seulement dans la gamme «latin-1». Merci! :) –