試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

Pythonにおけるエンコーディングの扱いとエンコーディングの変換について

(2010/11/1)本記事の内容はバージョン2系のPythonについて書かれている。バージョン3系ではエンコーディングの扱いが変わっており、「バージョン3系のPythonにおける文字列とそのエンコーディングに関する覚え書き(文字列型とバイト列型)」で扱っている。
(2014/11/20)リファレンスのリンク先を修正した。

  1. エンコーディングとエンコード/デコード操作
  2. エンコーディングの変換
  3. encode()やdecode()が失敗する場合について

エンコーディングエンコード/デコード操作

Pythonにおいて、UTF-8やCP932(WindowsShift_JIS)などのそれぞれのエンコーディングの文字列はUnicodeの文字列と相互に変換することができる。
エンコーディングエンコードされている文字列オブジェクトのメンバ関数decode()の引数にそのエンコーディング名を指定すると、それをデコードしてUnicode文字列のオブジェクトが得られる。逆に、Unicode文字列オブジェクトのメンバ関数encode()の引数にエンコーディング名を指定すると、それぞれのエンコーディングエンコードされた文字列のオブジェクトが得られる。

                         [EUC-JP文字列]
 eucjpstr.decode('euc-jp')  │     ↑ ucstr.encode('euc-jp')
                            ↓     │
utf8str.decode('utf-8') ─→         ─→ ucstr.encode('cp932')
[UTF-8文字列]            [Unicode文字列]          [CP932文字列]
  ucstr.encode('utf-8') ←─         ←─ cp932str.decode('cp932')
                            │     ↑
ucstr.encode('iso-2022-jp') ↓     │ iso2022jpstr.decode('iso-2022-jp')
                       [ISO-2022-JP文字列]

また、文字列定数(リテラル)の手前に「u」と付けたものは実行環境のエンコーディング*1からUnicode文字列にデコードされたものとなる。例えばUTF-8エンコーディングで「u'日本語'」としたものは「'日本語'.decode('utf-8')」の戻り値と同じになる。また、組み込み関数unicode()を用いた「unicode('日本語', 'utf-8')」の戻り値も同じものとなる。

(注意:UTF-8エンコーディングの端末におけるテスト)
>>> u'日本語' == '日本語'.decode('utf-8') == unicode('日本語', 'utf-8') == u'\u65e5\u672c\u8a9e'
True

エンコーディング名の一覧については
http://docs.python.jp/3/library/codecs.html#standard-encodings
にあり、あるエンコーディング名に対して別名も存在する。また、エンコーディング変換とは関係ないが、Base64やbzip2、hexといった特殊なものもコーデック名として指定して変換することができる。

エンコーディングの変換

エンコーディングの変換はUnicode文字列を中継してdecode()encode()を組み合わせて行う。

(注意:UTF-8エンコーディングの端末におけるテスト)

(UTF-8 <==> EUC-JP)
>>> '日本語'.decode('utf-8').encode('euc-jp')
'\xc6\xfc\xcb\xdc\xb8\xec'
>>> '\xc6\xfc\xcb\xdc\xb8\xec'.decode('euc-jp').encode('utf-8') == '日本語'
True

(UTF-8 <==> ISO-2022-JP)
>>> '日本語'.decode('utf-8').encode('iso-2022-jp')
'\x1b$BF|K\\8l\x1b(B'
>>> '\x1b$BF|K\\8l\x1b(B'.decode('iso-2022-jp').encode('utf-8') == '日本語'
True

(UTF-8 <==> CP932)
>>> '日本語'.decode('utf-8').encode('cp932')
'\x93\xfa\x96{\x8c\xea'
>>> '\x93\xfa\x96{\x8c\xea'.decode('cp932').encode('utf-8') == '日本語'
True

encode()やdecode()が失敗する場合について

上のencode()decode()は、当然のことながら、(元の)文字列オブジェクトの実際のエンコーディングと引数のエンコーディング名との関係によっては失敗する。例えば、CP932エンコーディングの文字列からUnicode文字列を得るのに「decode('utf-8')」とすると処理は失敗する。このように、正しくないエンコーディングが指定されたときにはUnicodeDecodeErrorという例外が発生する。

>>> '\x93\xfa\x96{\x8c\xea'.decode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.6/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0x93 in position 0: unexpected code byte

(2010/3/30)上の例はdecode()のものだが、Unicode文字列から特定のエンコーディングエンコード済みの文字列に対して更にencode()しようとしても例外が発生する。

(注意:UTF-8エンコーディングの端末におけるテスト)
>>> '日本語'.encode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 0: ordinal not in range(128)

上の「'日本語'」はUTF-8エンコードされているため、それをUTF-8エンコードすることはできない。一方、「u'日本語'」はUnicode文字列にデコードされているので、UTF-8エンコードすることができる。

(注意:UTF-8エンコーディングの端末におけるテスト)
>>> '日本語' == u'日本語'.encode('utf-8') == '\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e'
True

関連URL:

使用したバージョン:

*1:Pythonシェルなら端末、スクリプトならそのファイルのエンコーディング