2010-07-11 5 views
14

Possible en double:
Python UnicodeDecodeError - Am I misunderstanding encode?Python: désinfecter une chaîne pour unicode?

J'ai une chaîne que je suis en train de faire en toute sécurité pour la fonction unicode():

>>> s = " foo “bar bar ” weasel" 
>>> s.encode('utf-8', 'ignore') 

Traceback (most recent call last): 
    File "<pyshell#8>", line 1, in <module> 
    s.encode('utf-8', 'ignore') 
UnicodeDecodeError: 'ascii' codec can't decode byte 0x93 in position 5: ordinal not in range(128) 
>>> unicode(s) 

Traceback (most recent call last): 
    File "<pyshell#9>", line 1, in <module> 
    unicode(s) 
UnicodeDecodeError: 'ascii' codec can't decode byte 0x93 in position 5: ordinal not in range(128) 

Je suis surtout autour flailing ici. Que dois-je faire pour supprimer les caractères dangereux de la chaîne?

Un peu lié à ce question, bien que je n'ai pas pu résoudre mon problème.

Cela échoue aussi:

>>> s 
' foo \x93bar bar \x94 weasel' 
>>> s.decode('utf-8') 

Traceback (most recent call last): 
    File "<pyshell#13>", line 1, in <module> 
    s.decode('utf-8') 
    File "C:\Python25\254\lib\encodings\utf_8.py", line 16, in decode 
    return codecs.utf_8_decode(input, errors, True) 
UnicodeDecodeError: 'utf8' codec can't decode byte 0x93 in position 5: unexpected code byte 
+0

Je me demande pourquoi 'str' a une fonction' encodage' et si le paramètre 'encoding' spécifie le codage du résultat ou le codage de l'entrée. Qu'est-ce que tu essaies de faire ici? – Thanatos

+0

S'il vous plaît vérifier [this] (http://stackoverflow.com/questions/368805/python-unicodedecodeerror-am-i-misunderstanding-encode/370199#370199) répondre à une question connexe: "Python UnicodeDecodeError - Suis-je un code malentendu? " – tzot

+0

Pour ceux qui recherchent une solution pour désinfecter les caractères spéciaux unicode en (X) HTML, essayez' u'my unicode str'.encode ('ascii', 'xmlcharrefreplace') '. – toszter

Répondre

4

EDIT. On dirait que votre chaîne est codée de telle sorte que (DOUBLE COTATION DE COTATION GAUCHE) devient \x93 et (COT. DOUBLE COTATION DE COTATION) devient \x94. Il y a un certain nombre de pages de codes avec une telle cartographie, CP1250 est l'un d'entre eux, de sorte que vous pouvez utiliser ceci:

s = s.decode('cp1250') 

Pour tous les codepages quelle carte -\x93 voir here (tous également la carte à \x94 , qui peut être vérifiée here).

+0

Cet appel échoue pour moi (voir ci-dessus) –

+0

@Rosarch OK, maintenant je vois la chaîne d'origine. J'ai mis à jour la réponse (et pendant ce temps @darkporter avait trouvé la même solution). – Bolo

+0

Joli lien sur les pages de codes. On dirait qu'ils sont toutes des variations sur les "fenêtres" cependant. Si vous êtes "occidental" je dirais qu'il suffit de coller avec 1252. – jpsimons

37

Bonne question. Les problèmes d'encodage sont difficiles. Commençons par "J'ai une chaîne." Les chaînes de Python 2 ne sont pas vraiment des "chaînes", ce sont des tableaux d'octets. Donc, votre chaîne, d'où vient-elle et quel est son encodage? Votre exemple montre des guillemets dans le littéral, et je ne suis même pas sûr de la façon dont vous l'avez fait. J'essaie de le coller dans un interpréteur Python, ou de le taper sur OS X avec Option- [, et ça ne passe pas.

En regardant votre deuxième exemple si, vous avez un caractère hex 93. Ce ne peut pas être UTF-8, car en UTF-8, tout octet supérieur à 127 fait partie d'une séquence multi-octets. Donc je devine que c'est supposé être Latin-1. Le problème est que x93 n'est pas un caractère dans le jeu de caractères Latin-1. Il y a cette plage "invalide" dans Latin-1 de x7f à x9f qui est considérée comme illégale. Cependant, Microsoft a vu cette gamme inutilisée et a décidé d'y mettre des "guillemets". Ce faisant, ils ont créé ce codage similaire appelé "windows-1252", qui est comme Latin-1 avec des choses dans cette plage invalide. Donc, supposons qu'il s'agit de windows-1252. Et maintenant? String.decode convertit les octets en Unicode, c'est donc ce que vous voulez. Votre deuxième exemple était sur la bonne voie, mais il a échoué parce que la chaîne n'était pas UTF-8. Essayez:

>>> uni = 'foo \x93bar bar\x94 weasel'.decode("windows-1252") 
u'foo \u201cbar bar\u201d weasel' 
>>> print uni 
foo “bar bar” weasel 
>>> type(uni) 
<type 'unicode'> 

C'est correct, car l'ouverture de guillemets est Unicode U + 201C. Maintenant que vous avez Unicode, vous pouvez le sérialiser en octets dans n'importe quel encodage que vous choisissez (si vous avez besoin de le passer à travers le fil) ou simplement le garder en Unicode s'il reste dans Python. Si vous voulez convertir en UTF-8, utilisez la fonction opposée, string.encode.

>>> uni.encode("utf-8") 
'foo \xe2\x80\x9cbar bar \xe2\x80\x9d weasel' 

Les guillemets prennent 3 octets pour coder en UTF-8. Vous pourriez utiliser UTF-16 et ils ne seraient que deux octets. Vous ne pouvez pas encoder comme ASCII ou Latin-1, car ceux-ci n'ont pas de guillemets.

+1

+1, mais vous devriez aussi mentionner que cette réponse est spécifique à Python 2.x. Dans 3.x, le type 'str' est renommé en' bytes' et 'unicode' est renommé' str'. Bien que confus au début, ce changement rend ce genre de chose moins probable. –

+0

+1 pour "Commençons par 'J'ai une chaîne'" haha ​​ –

+1

@Daniel Ne pas être incestueux mais je viens de voter pour votre explication de vote-up. C'est vrai: ce qui précède est spécifique à Python 2.x. – jpsimons

Questions connexes