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

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

バージョン3系のPythonにおける文字列とそのエンコーディングに関する覚え書き(ファイル入出力とエンコーディング)

バージョン3系のPythonにおける文字列とそのエンコーディングに関する覚え書き(文字列型とバイト列型)」の続き。

ファイル読み込み時におけるエンコーディングの処理

バージョン3系のPythonでは、テキストファイルを読み込む場合、それを開く際に適切なエンコーディングを指定しておかないとファイルの内容を読み込んだときに例外(UnicodeDecodeError)が発生する。
ここではその動作を確認するための実験を行う。まずは
[任意]ファイル名: eucjp.txt エンコーディング: EUC-JP

これは
テスト
です。

このような内容のテキストファイルをEUC-JPのエンコーディングで保存しておく。
これをPythonで開くのだが、open()で正しくファイルが開けても、読み込みの段階で

(UTF-8でないエンコーディングのファイルを開いた場合)
>>> f = open ('eucjp.txt', 'r')
>>> f.read ()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.1/codecs.py", line 300, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xa4 in position 0: unexpected code byte

このようになり、例外の詳細を見るとUTF-8エンコーディングとして文字列型(Unicodeデータ)にデコードしようとして失敗している。このファイルの代わりにUTF-8エンコーディングで保存したテキストファイル(utf8.txtとする)を用意し、これを開いてみると

(UTF-8のエンコーディングのファイルを開いた場合)
(注意:UTF-8エンコーディングの端末におけるテスト)
>>> f = open ('utf8.txt', 'r')
>>> f.read ()
'これは\nテスト\nです。\n'

正しく処理できている。つまり、標準では入力をUTF-8エンコーディングとみなしてそれをデコードしようとしているが、他のエンコーディングのテキストファイルを読み込む際、UTF-8以外のエンコーディングとして処理をしたい場合には別の指定が必要ということになる。
それがopen()のキーワード引数encodingで、エンコーディング名を文字列で指定する。今回はEUC-JPとして処理したいので下のようにすると

(正しいエンコーディング名を指定した場合)
>>> f = open ('eucjp.txt', 'r', encoding='eucjp')
>>> f.read ()
'これは\nテスト\nです。\n'

うまく扱えている。これを間違ったエンコーディング名にすると(例として「cp932」とする)

(間違ったエンコーディング名を指定)
>>> f = open ('eucjp.txt', 'r', encoding='cp932')
>>> f.read ()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'cp932' codec can't decode bytes in position 3-4: illegal multibyte sequence

CP932としてのデコードを試み、失敗する。

ファイル書き込み時のエンコーディング指定

ファイル書き込み時のエンコーディング指定もopen()のキーワード引数encoding(省略時はUTF-8)で行い、write()などで書き込んだ文字列は自動的にそのエンコーディングに変換されて書き出される。

(EUC-JPのエンコーディングで保存)
>>> f = open ('eucjp.txt', 'w', encoding='eucjp')
>>> f.write ('テスト')
3
>>> f.close ()

(CP932のエンコーディングで保存)
>>> f = open ('cp932.txt', 'w', encoding='cp932')
>>> f.write ('テスト')
3
>>> f.close ()

(UTF-8のエンコーディングで保存)
>>> f = open ('utf8.txt', 'w')
>>> f.write ('テスト')
3
>>> f.close ()

このあたりは扱いやすい印象がある。

関連記事:

使用したバージョン: