UnicodeDecodeError, 無効なコンティニュエーションバイト

以下の項目で失敗し、"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")

の結果になります。

 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
ソリューション

0xE9は2進法では1110 1001のように見えます。UTF-8 on Wikipedia]1を読むと、このようなバイトの後には 10xx xxxx という形式のバイトが2つ続かなければならないことがわかります。ですから、例えばですが

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

しかし、これは例外の機械的な原因に過ぎません。この場合、ほぼ確実にlatin 1でエンコードされた文字列があります。UTF-8とlatin 1がどのように違うかを見ることができます。

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

(注意、ここではPython2と3の混在した表現を使っています。入力はどのバージョンのPythonでも有効ですが、あなたのPythonインタープリタが実際にユニコードとバイト文字列の両方をこのように表示することはないでしょう)。

解説 (2)

UTF-8では無効です。 その文字はISO-Latin1ではe-acute文字なので、そのコードセットでは成功します。

文字列を受け取るコードセットを知らないと、ちょっと困ったことになります。 プロトコルやアプリケーションに合わせて一つのコードセット(できればUTF-8)を選び、デコードできないものを拒否することができればベストです。

それができない場合は、ヒューリスティックが必要になります。

解説 (1)

UTF-8はマルチバイトであり、あなたが入力した \xe9 とそれに続くスペースの組み合わせに対応する文字は存在しません。

なぜ、UTF-8とlatin-1の両方で成功しなければならないのですか?

同じ文章がutf-8ではどうなるかというと。

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