UnicodeDecodeError, octet de continuation invalide

Pourquoi l'élément ci-dessous échoue-t-il ? et pourquoi réussit-il avec le codec "latin-1" ?

o = "a test of \xe9 char" #I want this to remain a string as this is what I am receiving
v = o.decode("utf-8")

résulte en :

 Traceback (most recent call last):  
 File "<stdin>", line 1, in <module>  
 File "C:\Python27\lib\encodings\utf_8.py",
 line 16, in decode
     return codecs.utf_8_decode(input, errors, True) UnicodeDecodeError:
 'utf8' codec can't decode byte 0xe9 in position 10: invalid continuation byte
Solution

En binaire, 0xE9 ressemble à 1110 1001. Si vous lisez [UTF-8 sur Wikipedia][1], vous verrez qu'un tel octet doit être suivi de deux octets de la forme 10xx xxxx. Donc, par exemple :

>>> b'\xe9\x80\x80'.decode('utf-8')
u'\u9000'

Mais ce n'est que la cause mécanique de l'exception. Dans ce cas, vous avez une chaîne qui est presque certainement encodée en latin 1. Vous pouvez voir comment UTF-8 et latin 1 sont différents :

>>> u'\xe9'.encode('utf-8')
b'\xc3\xa9'
>>> u'\xe9'.encode('latin-1')
b'\xe9'

[1] : http://en.wikipedia.org/wiki/UTF-8#Design

(Remarque : j'utilise ici un mélange de représentation de Python 2 et 3. L'entrée est valable dans n'importe quelle version de Python, mais il est peu probable que votre interpréteur Python affiche réellement les chaînes unicode et octet de cette manière).

Commentaires (2)

C'est un UTF-8 invalide. Ce caractère est le caractère e-acute dans l'ISO-Latin1, c'est pourquoi il réussit avec ce jeu de codes.

Si vous ne connaissez pas le jeu de codes dans lequel vous recevez les chaînes de caractères, vous risquez d'avoir des problèmes. Il serait préférable de choisir un seul jeu de codes (avec un peu de chance UTF-8) pour votre protocole/application, puis de rejeter ceux qui ne sont pas décodés.

Si vous ne pouvez pas faire cela, vous aurez besoin d'une heuristique.

Commentaires (1)

Parce que l'UTF-8 est multi-octet et qu'il n'y a pas de caractère correspondant à votre combinaison de `xe9 plus l'espace suivant.

Pourquoi devrait-elle réussir dans les utf-8 et latin-1 ?

Voici comment la même phrase devrait être en utf-8 :

>>> o.decode('latin-1').encode("utf-8")
'a test of \xc3\xa9 char'
Commentaires (1)