Pythonのopenで使用するencodingはプラットフォームに依存します。
Windowsであればcp932です。
Windows上のPythonでUTF-8で保存されたテキストファイルを
openのencoding引数に何もつけずに開くとエラーが発生します。
1 2 3 |
with open('UTF-8.txt') as f: s = f.read() print(s) # UnicodeDecodeError: 'cp932' codec can't decodeが発生する |
テキストファイルを開く前に文字コードを判別してから
適切なencoding引数で開くようにしてみます。
chardetを使用して文字コードを判別する
chardetを使用して、文字コードを判別します。

pipまたはcondaを使用してchardetをインストールします。
1 |
pip install chardet |
または
1 |
conda install chardet |
UTF-8とShift-JISの文字コードのテキストファイルを用意して、
それぞれ下記の内容でファイルを保存しました。
1 |
あいうえお |
このテキストファイルをchardetのdetectメソッドを使用して
テキストファイルの文字コードを判別してみます。
detectメソッドの引数にはbytesまたはbytearrayを渡す必要があります。
openでファイルを開くときにmodeの引数にrbを指定し
バイナリモードで読み込んだファイルをdetectの引数として使用します。
1 2 3 4 5 6 7 8 9 10 |
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())))) |
ファイルの文字コード、文字コードの確度、ファイルに書かれている言語を表示してくれます。
1 2 3 4 5 |
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と判別できました。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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())) |
1 2 3 4 5 |
kokoro_UTF-8.txt {'encoding': 'utf-8', 'confidence': 0.99, 'language': ''} kokoro_Shift-JIS.txt {'encoding': 'SHIFT_JIS', 'confidence': 0.99, 'language': 'Japanese'} |
文字コードを判別してからテキストファイルを開く
chardetのマニュアルに複数のファイルの文字コードを判別する方法が掲載されています。
こちらのコードを応用して、事前に文字コードを判別してから
テキストファイルを開いてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
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行目を表示します。
1 2 3 4 5 |
.\kokoro_Shift-JIS.txt こころ .\kokoro_UTF-8.txt こころ |
chardetは非常に便利ですが、ファイルの内容によっては
文字コードを誤認識する可能性があります。
文字コードの確度が低い場合は、手動で文字コードを指定してから
ファイルを読み込む必要がでてきます。
コメント