【Python】ファイルの文字コードを自動判定するchardetの使い方

外部システムから連携されたCSVファイルや、レガシーな環境で作成されたテキストファイルをプログラムで読み込む際、文字コード(エンコーディング)が不明であるために「文字化け」やエラーが発生することがある。

Pythonでファイルの文字コードを推定する場合、デファクトスタンダードとなっているライブラリが chardet である。ここでは、ファイルサイズに応じた適切な判定方法と、その実装コードを解説する。

目次

chardetのインストール

chardet は外部ライブラリであるため、以下のコマンドでインストールを行う。

pip install chardet

1. 小規模ファイルの文字コード判定

設定ファイルや小さなテキストデータの場合、ファイルの内容をすべて読み込んでから判定を行うのが最も簡単である。

実装例:受信データの一括判定

以下のコードは、ファイル全体をバイナリモードで読み込み、そのバイト列から文字コードを推定する例である。

import chardet

def detect_small_file_encoding(file_path):
    """
    小さなファイルの文字コードを判定して結果を表示する
    """
    try:
        # バイナリモード('rb')でファイルを開くことが必須
        with open(file_path, mode="rb") as f:
            # ファイル全体をバイト列として読み込む
            raw_data = f.read()
            
            # chardet.detect()にバイト列を渡して判定
            result = chardet.detect(raw_data)
            
            # 結果の出力
            print(f"--- {file_path} の判定結果 ---")
            print(f"推定エンコーディング: {result['encoding']}")
            print(f"確信度(信頼度)    : {result['confidence']}")
            print(f"言語              : {result['language']}")
            print(f"詳細データ        : {result}")

    except FileNotFoundError:
        print(f"エラー: ファイル '{file_path}' が見つかりませんでした。")

if __name__ == "__main__":
    # テスト用のダミーファイルを作成して判定
    # (実際には解析したい既存ファイルのパスを指定する)
    target_file = "sample_sjis.txt"
    with open(target_file, "w", encoding="shift_jis") as f:
        f.write("これはShift_JISで書かれたサンプルテキストです。")

    detect_small_file_encoding(target_file)

2. 大規模ファイルの高速判定

ログファイルなど、サイズが数百MB〜数GBに及ぶファイルの場合、全体をメモリに読み込む chardet.detect() はメモリ不足や処理遅延の原因となる。

そのような場合は、UniversalDetector クラスを使用する。これはデータを少しずつ読み込み(ストリーム処理)、判定が可能になった時点で処理を中断できるため、巨大なファイルでも高速かつ低メモリで動作する。

実装例:巨大ログファイルの判定

import chardet
from chardet.universaldetector import UniversalDetector

def detect_large_file_encoding(file_path):
    """
    大きなファイルを少しずつ読み込み、効率的に文字コードを判定する
    """
    # 検出器のインスタンスを作成
    detector = UniversalDetector()

    try:
        with open(file_path, mode="rb") as f:
            # ファイルを行単位(バイナリ)で読み込む
            for binary_line in f:
                # 検出器にデータを供給する
                detector.feed(binary_line)
                
                # 判定が完了したかチェック(doneがTrueになれば確定)
                if detector.done:
                    break
        
        # データの供給が終わったら必ずclose()を呼ぶ
        detector.close()
        
        # 結果の取得
        result = detector.result
        
        print(f"--- {file_path} (大規模想定) の判定結果 ---")
        print(f"推定エンコーディング: {result['encoding']}")
        print(f"確信度              : {result['confidence']}")
    
    except FileNotFoundError:
        print(f"エラー: ファイル '{file_path}' が見つかりませんでした。")

if __name__ == "__main__":
    # テスト用のダミーファイル
    large_target = "system_log_utf8.log"
    with open(large_target, "w", encoding="utf_8") as f:
        # 判定に必要なデータ量は通常ごくわずかで済む
        f.write("2023-10-01 [INFO] サーバー起動処理を開始します。\n" * 100)

    detect_large_file_encoding(large_target)

結果辞書の内容について

判定結果(result)は辞書型で返され、以下のキーを持つ。

  • encoding: 推定された文字コード(例: 'utf-8', 'SHIFT_JIS', 'EUC-JP')。判定不能な場合は None
  • confidence: 判定の確信度。0.0〜1.0の間の浮動小数点数で、1.0に近いほど信頼性が高い。
  • language: 推定された言語(例: 'Japanese')。

不特定多数のファイルを扱うバッチ処理などでは、この confidence の値をチェックし、信頼度が低い場合は処理をスキップしたり警告を出したりする実装が推奨される。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次