文字コードの判定について調べたメモ
ある文字列の文字コードがなにか調べたい。予備知識としては、
- 正確にはできない
- 判定対象の文字数が少ないと厳しい
という感じだったが、少し突っ込んで調べたのでメモしておく。
Charset detection
Wikipediaから。
テキストを表す一連のバイトの文字エンコードをヒューリスティックに推測するプロセスです。 この手法は信頼できないと認識されており、HTTPのContent-Typeヘッダーが利用できないか、信頼できないと見なされる時に限って使用されます。 このアルゴリズムは通常、検出される各コードページでエンコードされたさまざまな言語の3文字表記の頻度分布など、バイトパターンの統計分析を伴います。 そのような統計分析は、言語検出の実行にも使用できます。このプロセスは統計データに依存するため、絶対確実なわけではありません。 https://en.wikipedia.org/wiki/Charset_detection
日本語訳は全てGoogle翻訳です
ICU
実装としてICUというのを知った。
文字セットの検出は、未知の形式の文字データの文字セットまたはエンコードを決定するプロセスです。これは、せいぜい、統計とヒューリスティックを使用した不正確な操作です。このため、検出は、ほとんどが単一の言語である文字データを少なくとも数百バイト提供する場合に最適に機能します。場合によっては、エンコーディングとともに言語を決定できます。
文字セットの検出には、いくつかの異なる手法が使用されます。マルチバイトエンコーディングの場合、バイトシーケンスの正当なパターンがチェックされます。また、検出された文字は、そのエンコーディングで頻繁に使用される文字のリストと照合されます。 http://userguide.icu-project.org/conversion/detection
公式ではなさそうだがGoの実装もある
Compact Encoding Detector
もう一つの実装としてこれを見つけたけど、ちゃんと見てません。
Chromiumで使われてる? https://chromium.googlesource.com/external/github.com/google/compact_enc_det/
ICUの判定ロジック
雑に読んだだけなので間違ってるかもしれない。
- 文字コード別に候補文字の集合を定義しておく
- 判定対象の文字列に対して、それぞれの文字コードの候補文字集合から何個マッチするか調べる
- なんか調整して0〜100の評価値を決める
- 評価値が一番高い文字コードが優勝
読んだコードはこの辺り。
- icu/csrmbcs.cpp at master · unicode-org/icu
- icu/csdetect.cpp at master · unicode-org/icu
- chardet/multi_byte.go at master · saintfish/chardet
候補文字の集合がどうなってるか気になる。Shift_JISの場合はこれだった。
、。・ー()「」あいうかがきくけこさしすただってでとなにのはまもらりるれをんアイクグスタットブプラリルロン事日分
確認に使ったコード https://play.golang.org/p/fq41Rz97t1P