Pythonのバイト文字列とユニコード文字列のお話

はじめに

Pythonは非常に気持ちいい言語である。しかしunicodeを扱おうと思ったとたん、イライラさせられる。日本人のプログラマーRubyを使っている人が多いけど、このあたりの違いによる物なのかなぁ〜と勝手に思ってみたり、、、


さて本題


マルチバイト文字について

str型は1文字=1バイトのバイト列として文字列を扱う。しかし日本語の場合1バイトでは全ての文字を表現しきれないので、1文字に対して複数バイトを割り当てるマルチバイトコーディングが利用されている。

MS-DOSでは、デフォルトでshift-JISが使われている。shift-JISは2バイト目に\が使われる場合がある。具体的には漢字の’表’カタカナの’ソ’がこれにあたる。\はWindowsでパスの区切りなどに使われており、誤認されることがある。


>>> s = '表a\\ソ連.txt'
>>> s
'\x95\\a\\\x83\\\x98A.txt'
>>> s.split(os.path.sep)
['\x95', 'a', '\x83', '\x98A.txt']

つまり、ファイルパス(フォルダ名やファイル名)に表やソが混じっていると予期せぬところでパスが区切られてしまう。



Unicodeにまつわるエラー

unicode型とstr型の操作はunicodeに自動変換されて行われる。

>>> 'abc' == u'abc'
True
>>> 'abc' + u'abc'
u'abcabc'
したがってASCIIがカバーしている範囲(英数字)であれば比較や、演算も問題ない。

問題を起こすのは下記の様に、unicode型と日本語が入っているstr型を比較したときである。


>>> u'abc' + 'あ'
Traceback (most recent call last):
File "", line 1, in
UnicodeDecodeError: 'ascii' codec can't decode byte 0x82 in position 0: ordinal
not in range(128)

このエラーは日本語が入っているstr型'あ'をASCIIコードでデコードしてunicode型に変換しようとしたらASCIIコードの範囲外(ASCIIコードは0x00から0x7fまで)の0x82が出てきて変換できませんと怒られている。


unicodeを扱うときのコツ

Pythonunicodeを扱うときのコツは、unicode型はあくまで文字の入れ物であり、utf-8やshift-jisなどの文字コードとは別物であると意識するところにある。実際ここでつまずくプログラマ(私も含めて)は、unicode型とユニコードと言われている文字コード(utf-8utf-16)とを同じものと間違った理解をしていることが原因だと思う。