Pythonのopenで使用するencodingはプラットフォームに依存します。
Windowsであればcp932です。
Windows上のUTF-8で保存されたテキストファイルをencoding引数に何もつけずにopenするとエラーが発生します。
with open('UTF-8.txt') as f:
s = f.read()
print(s) # UnicodeDecodeError: 'cp932' codec can't decodeが発生する
テキストファイルを開く前に文字コードを判別してから適切なencoding引数で開くようにしてみます。
chardetを使用して文字コードを判別する #
chardetを使用して、文字コードを判別します。
pipを使用してchardetをインストールします。
pip install chardet
UTF-8とShift-JISの文字コードのテキストファイルを用意して、それぞれ下記の内容でファイルを保存しました。
あいうえお
このテキストファイルをchardetのdetectメソッドを使用してテキストファイルの文字コードを判別してみます。
detectメソッド
の引数にはbytes
またはbytearray
を渡す必要があります。
open
でファイルを開くときにmode
の引数にrb
を指定し、バイナリモードで読み込んだファイルを
detect
の引数として使用します。
import chardet
with open('UTF-8.txt', 'rb') as f:
print('UTF-8.txt')
print(chardet.detect(f.read()))
print()
with open('Shift-JIS.txt', 'rb') as f:
print('Shift-JIS.txt')
print(chardet.detect(f.read()))
ファイルの文字コード、文字コードの確度、ファイルに書かれている言語を表示してくれます。
UTF-8.txt
{'encoding': 'utf-8', 'confidence': 0.9690625, 'language': ''}
Shift-JIS.txt
{'encoding': 'Windows-1252', 'confidence': 0.73, 'language': ''}
UTF-8のファイルは判別できていますが、Shift-JISのファイルは間違った文字コードとして判別しています。
bytes
の内容から判別を行っているようですがbytes
の元となるテキストファイルの内容によっては
うまく判別できないようです。
青空文庫(夏目漱石の「こころ」)のファイルを利用してテストしてみたところ正常にUTF-8とShift-JISと判別できました。
import chardet
# 文字コードUTF-8の「こころ」テキストファイル
with open('kokoro_UTF-8.txt', 'rb') as f:
print('kokoro_UTF-8.txt')
print(chardet.detect(f.read()))
print()
# 文字コードShift-JISの「こころ」テキストファイル
with open('kokoro_Shift-JIS.txt', 'rb') as f:
print('kokoro_Shift-JIS.txt')
print(chardet.detect(f.read()))
kokoro_UTF-8.txt
{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}
kokoro_Shift-JIS.txt
{'encoding': 'SHIFT_JIS', 'confidence': 0.99, 'language': 'Japanese'}</pre>
文字コードを判別してからテキストファイルを開く #
chardetのマニュアルに複数のファイルの文字コードを判別する方法が掲載されています。
こちらのコードを応用して、事前に文字コードを判別してからテキストファイルを開いてみます。
import glob
from chardet.universaldetector import UniversalDetector
def detect_character_code(pathname):
"""
pathnameから該当するファイルの文字コードを判別して
ファイル名と文字コードのdictを返す
:param pathname: 文字コードを判別したいフォルダ
:return: ファイル名がキー、文字コードが値のdict
"""
files_code_dic = {}
detector = UniversalDetector()
for file in glob.glob(pathname):
with open(file, 'rb') as f:
detector.reset()
for line in f.readlines():
detector.feed(line)
if detector.done:
break
detector.close()
files_code_dic[file] = detector.result['encoding']
return files_code_dic
if __name__ == '__main__':
# カレントフォルダ内のテキストファイルの文字コードを判別
path = './'
filename = '*'
extension = 'txt'
pathname = path + filename + '.' + extension
files_code = detect_character_code(pathname)
for filename in glob.glob(pathname):
with open(filename, encoding=files_code[filename]) as f:
for line in f.readlines():
print(filename)
print(line)
break
コードを動かすとカレントフォルダ内のテキストファイルの文字コードを判別してからテキストファイルを開きます。 開いたファイルの名前と、ファイルの内容の1行目を表示します。
.\kokoro_Shift-JIS.txt
こころ
.\kokoro_UTF-8.txt
こころ
chardetは非常に便利ですが、ファイルの内容によっては文字コードを誤認識する可能性があります。 文字コードの確度が低い場合は、手動で文字コードを指定してからファイルを読み込む必要がでてきます。