文字コードとの戦い (2) Unicode,エンコード,utf-8とは?
Python 2.xを使っている限り,文字コードとの戦いは避けられない. 今回は,文字コードについて調べたので,基礎的な事を備忘録としてまとめておく.
Python2.xでは何も指定しない限り,つまりデフォルトでは,
文字列はstr
オブジェクトとして認識され,エンコーディングする際はASCIIが指定される.
エンコーディングを理解する上で,ユニコードの説明が書かせないためユニコードの説明を行う. 下図にユニコードとバイト列(数値の列)の関係を示す. まず,理解しておきたいのはUnicode(ユニコード)とはUnify codeである, つまりコードを1つにするという意味である.あらゆる文字列を1つのコードで表現出来るようにしたコードである.
例えば,shift-jis
でエンコードされた文字列(str
オブジェクト)をutf-8
でエンコードした文字列にしたいときは,一度ユニコードに直してからutf-8
に変換する必要がある.
また,エンコードとはユニコードをバイト列に変換する事を示し,下図の例では,
utf-8
でエンコードするとバイト列は'\xe3\x81\x84'
になり,shift-jis
で
エンコードすると'\x82\xa0'
のバイト列で表現できる.
まだ理解するのが難しいかもしれないので,実際の例を見てみよう.
例1
*この例ではIPythonの命令を一部利用している
IPythonにはobject?
とするとobject
のtype
などの情報を表示する便利な機能がある.
今回はその機能を利用している.In[n] はn回めに行われたinputを表しており, Out[n]はoutputである.
In [66]: uni = u'あ' #ユニコードで`あ`を表現 In [66]: uni Out[66]: u'\u3042' #ユニコードのバイト列 In [67]: uni? Type: unicode Length: 1
この例では,あ
の前にu
を加えあ
をユニコードで表現し,uni
に代入した.
また,uni
はunicode
オブジェクトである.str
オブジェクトではない.
例2
次に,先程のユニコード文字を格納したuni
をutf-8
でエンコードすると以下のようになる.
In [127]: uni Out[127]: u'\u3042' In [130]: after_encoding = uni.encode('utf-8') In [131]: after_encoding Out[131]: '\xe3\x81\x82' In [132]: after_encoding? Type: str String Form:あ Length: 3
エンコードする事により'\xe3\x81\x82'
のようなバイト列が得られる.
また,これはstr
オブジェクトであり,私の環境ではあ
と出力される.
例3
続いて,ユニコード文字を格納したuni
をshift-jis
でエンコードする.
In [133]: shift_jis_encoding = uni.encode('shift-jis') In [134]: shift_jis_encoding Out[134]: '\x82\xa0' In [135]: shift_jis_encoding? Type: str String Form:�� #私の環境では??となる Length: 2
ユニコードをshift-jis
でエンコードすることにより,バイト列'\x82\xa0'
が得られ,
これもstr
オブジェクトである.しかし,私の環境ではshift-jis
でエンコードされた文字列を
確認する事ができない.なぜなら,私の標準出力ではshift-jis
エンコードには対応していないからだ.私の標準出力の設定をShift-jis
とすればあ
と出力されるだろう.
まとめ
今回,shift-jis
でエンコードされた文字を確認できなかったのは,私が使用している環境では,出力先(標準出力)がutf-8
しかサポートしていなかったためである.もし,shift-jis
のエンコードをサポートしている場合はあ
が表示され,utf-8
でエンコードされた文字は別の文字で表現されるだろう.例えば??
など(確認していないため正確にはわからない)
また,ユニコードにすることでマルチバイト文字列を様々な関数に適応することができる.
例えば,今回の例ではunicodeであ
を表現した時のみlength = 1
と適切に関数が
適応されている.このようにユニコードにすることで様々な関数への適応,様々な文字コードへエンコードすることが可能となる.出力以外の文字をユニコードにすることで,様々な文字コードへのエンコーディングが用意になることから,出力の時にだけエンコードするのが良いと思う.