📝

chardetの文字コード誤判定を回避する ― Pythonで安全な文字コード判定ロジックの実装

に公開

はじめに

Pythonでテキストファイルを扱う際、文字コードの自動判定が必要になることがあります。
多くのエンジニアが頼るのが chardetnkf ライブラリ化と思いますが、必ずしも完璧ではありません。

実際にきょう私は業務で、chardetを使っていて、Shift_JISのテキストファイルがWindows-1252と誤判定されるという事象に直面しました。
本記事では、その問題の再現と、業務で採用した安全な文字コード判定ロジックをご紹介します。

問題の発端:Shift_JISがWindows-1252と誤判定される

import chardet

with open("sample_sjis.txt", "rb") as f:
    raw_data = f.read()
    result = chardet.detect(raw_data)

print(result)

出力例

{'encoding': 'Windows-1252', 'confidence': 0.73, 'language': ''}

Shift_JISファイルなのに、Windows-1252 と判定されました。

なぜ誤判定が起きるのか?

  • Shift_JISとWindows-1252のバイト表現が一部似ている
  • chardet は統計的推定に基づいており、誤差が避けられない
  • 英数字中心の日本語ファイルは特に誤判定されやすい

解決策:主要な文字コードを優先的に試す

chardet を最後の手段にして、一般的に使用が想定される主要なエンコーディングを先に順番に試みることで、安全性を確保します。

from pathlib import Path
import chardet

COMMON_ENCODINGS = ["utf-8", "shift_jis", "euc_jp", "iso2022_jp"]

def detect_encoding(filepath: Path) -> str:
    content = filepath.read_bytes()

    for enc in COMMON_ENCODINGS:
        try:
            content.decode(enc)
            return enc
        except UnicodeDecodeError:
            continue

    # 最終手段として chardet
    result = chardet.detect(content)
    return result["encoding"] or "utf-8"

# 使用例
file_path = Path("sample_sjis.txt")
detected = detect_encoding(file_path)
print(f"Detected encoding: {detected}")

まとめ

  • chardet は便利だが、誤判定のリスクがある
  • よく使われる文字コードを先に試すことで安全性を確保できる

Discussion