【Python】テキストファイルの文字コードを判別してファイルを開く
Pythonのopenで使用するencodingはプラットフォームに依存します。
Windowsであればcp932です。
Windows上のUTF-8で保存されたテキストファイルをencoding引数に何もつけずにopenするとエラーが発生します。
1with open('UTF-8.txt') as f:
2 s = f.read()
3 print(s) # UnicodeDecodeError: 'cp932' codec can't decodeが発生する
テキストファイルを開く前に文字コードを判別してから適切なencoding引数で開くようにしてみます。
chardetを使用して文字コードを判別する
chardetを使用して、文字コードを判別します。
https://pypi.org/project/chardet/
pipを使用してchardetをインストールします。
1pip install chardet
UTF-8とShift-JISの文字コードのテキストファイルを用意して、それぞれ下記の内容でファイルを保存しました。
1あいうえお
このテキストファイルをchardetのdetectメソッドを使用してテキストファイルの文字コードを判別してみます。
detectメソッドの引数にはbytesまたはbytearrayを渡す必要があります。
openでファイルを開くときにmodeの引数にrbを指定し、バイナリモードで読み込んだファイルを
detectの引数として使用します。
1import chardet
2
3with open('UTF-8.txt', 'rb') as f:
4 print('UTF-8.txt')
5 print(chardet.detect(f.read()))
6
7print()
8with open('Shift-JIS.txt', 'rb') as f:
9 print('Shift-JIS.txt')
10 print(chardet.detect(f.read()))
ファイルの文字コード、文字コードの確度、ファイルに書かれている言語を表示してくれます。
1UTF-8.txt
2{'encoding': 'utf-8', 'confidence': 0.9690625, 'language': ''}
3
4Shift-JIS.txt
5{'encoding': 'Windows-1252', 'confidence': 0.73, 'language': ''}
UTF-8のファイルは判別できていますが、Shift-JISのファイルは間違った文字コードとして判別しています。
bytesの内容から判別を行っているようですがbytesの元となるテキストファイルの内容によっては
うまく判別できないようです。
青空文庫(夏目漱石の「こころ」)のファイルを利用してテストしてみたところ正常にUTF-8とShift-JISと判別できました。 https://www.aozora.gr.jp/cards/000148/card773.html
1import chardet
2
3# 文字コードUTF-8の「こころ」テキストファイル
4with open('kokoro_UTF-8.txt', 'rb') as f:
5 print('kokoro_UTF-8.txt')
6 print(chardet.detect(f.read()))
7
8print()
9
10# 文字コードShift-JISの「こころ」テキストファイル
11with open('kokoro_Shift-JIS.txt', 'rb') as f:
12 print('kokoro_Shift-JIS.txt')
13 print(chardet.detect(f.read()))
1kokoro_UTF-8.txt
2{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}
3
4kokoro_Shift-JIS.txt
5{'encoding': 'SHIFT_JIS', 'confidence': 0.99, 'language': 'Japanese'}</pre>
文字コードを判別してからテキストファイルを開く
chardetのマニュアルに複数のファイルの文字コードを判別する方法が掲載されています。
こちらのコードを応用して、事前に文字コードを判別してからテキストファイルを開いてみます。
https://chardet.readthedocs.io/en/latest/usage.html#example-detecting-encodings-of-multiple-files
1import glob
2from chardet.universaldetector import UniversalDetector
3
4
5def detect_character_code(pathname):
6 """
7 pathnameから該当するファイルの文字コードを判別して
8 ファイル名と文字コードのdictを返す
9
10 :param pathname: 文字コードを判別したいフォルダ
11 :return: ファイル名がキー、文字コードが値のdict
12 """
13 files_code_dic = {}
14 detector = UniversalDetector()
15 for file in glob.glob(pathname):
16 with open(file, 'rb') as f:
17 detector.reset()
18 for line in f.readlines():
19 detector.feed(line)
20 if detector.done:
21 break
22 detector.close()
23 files_code_dic[file] = detector.result['encoding']
24 return files_code_dic
25
26
27if __name__ == '__main__':
28 # カレントフォルダ内のテキストファイルの文字コードを判別
29 path = './'
30 filename = '*'
31 extension = 'txt'
32 pathname = path + filename + '.' + extension
33 files_code = detect_character_code(pathname)
34 for filename in glob.glob(pathname):
35 with open(filename, encoding=files_code[filename]) as f:
36 for line in f.readlines():
37 print(filename)
38 print(line)
39 break
コードを動かすとカレントフォルダ内のテキストファイルの文字コードを判別してからテキストファイルを開きます。
開いたファイルの名前と、ファイルの内容の1行目を表示します。
1.\kokoro_Shift-JIS.txt
2こころ
3
4.\kokoro_UTF-8.txt
5こころ
chardetは非常に便利ですが、ファイルの内容によっては文字コードを誤認識する可能性があります。
文字コードの確度が低い場合は、手動で文字コードを指定してからファイルを読み込む必要がでてきます。
関連ページ
- 【Python】keras-yolo3を使用して物体検出
- Anacondaで作成した仮想環境をJupyter NotebookのKernelに追加する
- Windows10にTensorFlow GPUとKerasをインストールする