UnicodeDecodeError, ungültiges Fortsetzungsbyte

Warum schlägt das unten stehende Element fehl und warum gelingt es mit dem 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")

führt zu:

 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
Lösung

Im Binärformat sieht 0xE9 aus wie 1110 1001. Wenn du über UTF-8 auf Wikipedia liest, wirst du sehen, dass auf ein solches Byte zwei Bytes der Form "10xx xxxx" folgen müssen. Also, zum Beispiel:

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

Aber das ist nur die mechanische Ursache für die Ausnahme. In diesem Fall haben Sie eine Zeichenkette, die mit ziemlicher Sicherheit in Latin 1 kodiert ist. Sie können sehen, wie unterschiedlich UTF-8 und Latin 1 aussehen:

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

(Beachten Sie, dass ich hier eine Mischung aus der Darstellung von Python 2 und 3 verwende. Die Eingabe ist in jeder Python-Version gültig, aber es ist unwahrscheinlich, dass Ihr Python-Interpreter sowohl Unicode- als auch Byte-Strings auf diese Weise darstellt).

Kommentare (2)

Es ist ungültig UTF-8. Dieses Zeichen ist das e-acute-Zeichen in ISO-Latin1, weshalb es mit diesem Codesatz erfolgreich ist.

Wenn Sie den Codesatz, in dem Sie Zeichenketten empfangen, nicht kennen, haben Sie ein kleines Problem. Am besten wäre es, wenn Sie einen einzigen Codesatz (hoffentlich UTF-8) für Ihr Protokoll/Ihre Anwendung auswählen und dann nur diejenigen zurückweisen, die nicht decodiert werden können.

Wenn Sie das nicht tun können, brauchen Sie Heuristiken.

Kommentare (1)

Weil UTF-8 ein Multibyte-Format ist und es kein Zeichen gibt, das Ihrer Kombination aus "xe9" und dem folgenden Leerzeichen entspricht.

Warum sollte es in beide UTF-8 und Latin-1 gelingen?

Hier sehen Sie, wie derselbe Satz in UTF-8 aussehen sollte:

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