スプーキーズのちょっとTech。

SPOOKIES社内のより技工的な、専門的なブログページです。

CSV文字コード変換アプリのエンコーディング判定

こんにちは、spookies歴2か月目の下釜です!
今回は、CSVファイルの文字コード自動判定処理で発生した問題と、その対策について共有します。特に、jschardet を使っている方や、CSVの文字コードでハマった経験がある方に参考になれば嬉しいです。

問題内容

jschardet を使ってCSVファイルの文字コードを自動判定していたが、以下のようなケースでエラーが発生した:

  • 文字コードの confidence が低すぎて undefined になる

  • ファイルの内容が英数字中心で判定が困難(ASCIIと誤認識)

  • 結果として "xxx の文字コードを特定できませんでした" という例外が発生

原因

jschardet は、文字数が少なかったり、内容が英数字ばかりのCSVなどは正しく判定できない
UTF-8でもShift_JISでも解釈できるようなファイルだと、confidenceが低くなりやすい

対応内容

元のコード(変更前)

const detected = jschardet.detect(buffer);
const encoding = detected?.encoding?.toLowerCase();
if (!encoding || detected.confidence < 0.3) {
  throw new Error(`${file.name} の文字コードを特定できませんでした`);
}
const supportedEncodings = ['utf-8', 'ascii', 'shift_jis', 'windows-1252'];
if (!supportedEncodings.includes(encoding)) {
  throw new Error(`${file.name} は未対応の文字コードです(推定: ${encoding})`);
}
const decodedText = iconv.decode(buffer, encoding);

変更後のコード(修正後)

const detected = jschardet.detect(buffer);
let encoding = detected?.encoding?.toLowerCase() || '';
// 英数字のみか判定
const asciiOnly = /^[\x00-\x7F]*$/.test(buffer.toString('binary'));
// encoding 不明 or confidence 低い or 英数字だけなら shift_jis にフォールバック
if (!encoding || detected.confidence < 0.2 || asciiOnly) {
  encoding = 'shift_jis';
}
const supportedEncodings = ['utf-8', 'ascii', 'shift_jis', 'windows-1252'];
if (!supportedEncodings.includes(encoding)) {
  throw new Error(`${file.name} は未対応の文字コードです(推定: ${encoding})`);
}
const decodedText = iconv.decode(buffer, encoding);

修正内容の要点

  • confidence の判定閾値を緩和 0.3 → 0.2 に変更

  • エンコーディング未判定時に、shift_jisにフォールバックする

  • 英数字だけのファイル対策でASCII文字だけか判定し、同様に shift_jis へフォールバック

  • iconv-lite による変換処理自体は変更なし、判定部分のみ修正で済ませた

検証結果

  • マイナビのCSVなど、これまで読み込み時にエラーになっていたファイルもすべて取り込み可能になった

  • 日本語や記号の文字化けも発生せず、変換後はBOM付きUTF-8として正しくダウンロードされる

まとめ

CSVの文字コードは「なんとなくUTF-8でしょ」で済まないことが多く、特に日本語圏では Shift_JIS や Windows-1252 の混在がよくあります。 jschardet は便利ですが過信せず、フォールバック戦略を用意しておくことが安定運用のカギだと痛感しました。

同じように CSV ファイルの読み込み処理で困っている方の参考になれば幸いです!