はじめに
今更かもしれないが、Python で日本語の文字コード(エンコーディング)を判定する方法について。
最近必要になってググってみると chardet
を使って判定する記事が多い。「じゃあ……」と思って使ってみたが、どうもうまくいかない。
というわけで、自分でこしらえてみた、という話。
コード
前提として、自分の場合、日本語と ASCII くらいしか想定していない(つまり他の国特有のコードを想定していない)、ということがある。
jp.py
# -*- coding: utf-8 -*-
JP_ENCODE = 'iso2022_jp', 'euc-jp', 'shift-jis', 'cp932', 'utf-8'
def decode(buf):
for c in JP_ENCODE:
try:
r = buf.decode(c) # まず decode してみる
try:
r.encode('ascii') # ascii で encode できたら、それは ascii
return r, 'ascii'
except UnicodeEncodeError:
return r, c # ダメなら c を返す
except UnicodeDecodeError:
pass
return str(buf), '' # 最後のあがき(w
if __name__ == '__main__':
import chardet
text = 'これはひらがなと漢字だけ。片仮名があると違うんだろう。たぶん'
# text = 'これはひらがなと漢字だけ。カタカナがあると違うんだろう。たぶん'
# text = 'これはひらがなと漢字だけ。①があると違うんだろう。たぶん'
# text = 'This is ascii only, abcABC012()[]_@#$'
for c in JP_ENCODE:
try:
buf = text.encode(c)
except UnicodeEncodeError:
print(c, '... skip')
continue
print(c)
print(decode(buf))
print(chardet.detect(buf))
print()
テスト
実行
$ python -V
Python 3.10.6
$ pip list | grep char
chardet 5.2.0
$ python jp.py
iso2022_jp
('これはひらがなと漢字だけ。片仮名があると違うんだろう。たぶん', 'iso2022_jp')
{'encoding': 'ISO-2022-JP', 'confidence': 0.99, 'language': 'Japanese'}
euc-jp
('これはひらがなと漢字だけ。片仮名があると違うんだろう。たぶん', 'euc-jp')
{'encoding': 'EUC-JP', 'confidence': 1.0, 'language': 'Japanese'}
shift-jis
('これはひらがなと漢字だけ。片仮名があると違うんだろう。たぶん', 'shift-jis')
{'encoding': None, 'confidence': 0.0, 'language': None}
cp932
('これはひらがなと漢字だけ。片仮名があると違うんだろう。たぶん', 'shift-jis')
{'encoding': None, 'confidence': 0.0, 'language': None}
utf-8
('これはひらがなと漢字だけ。片仮名があると違うんだろう。たぶん', 'utf-8')
{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}
ひらがなと漢字しか無いような shift-jis/cp932 のテキストは、chardet
としては難しいらしい。
関数 decode
も、shift-jis と cp932 の区別は、特定の文字が入っていないこのテキストでは流石に難しい(というか無理)なんで、そこはご愛嬌。
終わりに
この方法がベストプラクティスだ、とか言うつもりはない。
前述もしたが、前提として自分が必要としたのは一般的に使われているであろう日本語エンコーディングだけ。それだけに特化した手法とそれ以外も想定している手法では、前提が違うのだから公平な比較にならない。
それだけはここに重ねて追記しておく。