Windows C++ SDK
あるテキストファイルが与えられたときに、
そのファイルの文字コードを判定する
アルゴリズムを探しています。
判定したい文字コードは、
utf-8
utf-16(LE/BE)
Shift-JIS(Windows-31J,ASCII含む)
ISO-2022-JP
EUC-JP
です。
BOM付のutf-8,utf-16と、ISO-2022-JPは判定できます
現在考えている流れは、
if(BOMがある){
BOMに応じたエンコード
}else if(utf-16LEである){
utf-16LE
}else if(utf-16BEである){
utf-16BE
}else{
if(エスケープシーケンス){
ISO-2022-JP
}else{
int possible[4]={0};//u8,sj,jis,euc
{ //utf-8としてみてみる
1バイトずつ
ありえるバイトならpossible[0]++
可能性低めなら何もしない
不可能なバイトならpossible[0]=-1でループ抜ける
}
{ //shift-jisとしてみてみる
1バイトずつ
ありえるバイトならpossible[1]++
可能性低めなら何もしない
不可能なバイトならpossible[1]=-1でループ抜ける
}
{ //jisとしてみてみる
1バイトずつ
ありえるバイトならpossible[2]++
可能性低めなら何もしない
不可能なバイトならpossible[2]=-1でループ抜ける
}
{ //eucとしてみてみる
1バイトずつ
ありえるバイトならpossible[3]++
可能性低めなら何もしない
不可能なバイトならpossible[3]=-1でループ抜ける
}
possibleが一番高いものを選ぶ
}
}
このとき、utf-8テキストでもshift-jisのほうがpossibleが高くなります
どういうことでしょうか
このような目的のためには1バイト(1オクテット)単位でのチェックでは不足で
連続するバイト(オクテット)の組み合わせによる妥当性を考察する必要がある。
あと、短文(1単語程度)の場合、原理的に判断不能(人間でも無理)なんだけど
その辺はどう対応する予定かな?
亜 1文字を取るとき
cp932 (shift-jis, windows-31j) だと 88 9F
euc-japan だと B0 A1
utf-8 だと E4 BA 9C
B0 A1 は cp932 だと 半角カタカナの ー。
E4 BA は cp932 だと 莠 9C も単独では cp932 の l/t octet として認められる。
のように、コードがかぶっている。
BOM に頼るのは良くない。UTF-16 なら常に BOM がついているとは限らない。
(たとえば、俺んちでは BOM つき UTF-16 での保存は禁止している)
短文の場合に判断ミスが出てしまうのは仕方ないと思います。ここでは考えないことにし
ました。
>このような目的のためには1バイト(1オクテット)単位でのチェックでは不足で
>連続するバイト(オクテット)の組み合わせによる妥当性を考察する必要がある。
となるとどのような処理を行うべきでしょうか?
現在考えているのは
8bit目がなくてエスケープシーケンスがある→ISO2022JP
何らかの方法でUTF16を判定する
UTF-8の判定は、Wikipedia UTF-8 で何とかなりそうです。
Shift-JISとEUCJPを何らかの方法で判別する
UTF16についてはずっと困っています。
また、SJISとEUCJPもわかりません
この辺、自作するのは開発コストの問題で割に合わないと思うのだが・・・
自作しなきゃならない理由が何かある、のなら別だが、
俺なら libiconv とか IBM ICU とか既存のライブラリを使う。
変換元に *** を指定して、変換できたらその encoding が使われている、とするだけ。
sjis ってあっさり言ってるけど 本当に狭義の sjis を使いたいの?
本当は Windows-31j ないしは cp932 ではないの?
euc は euc-jp だけでいいの? euc-cn, euc-kr とか考えなくていいの?
などなど言い始めるとますますもって自作したくないんだが。
SJISとは今回はcp932を指します
また、eucはjpだけでいいです。
iconvの使用ですが、インストールが必要みたいなのですが、どういうことなのでしょうか?
IBM ICUはUNICODEのみなのでやめておきます
また、iconv,ICUともにLinux用の解説しかないのでよく分かりません。
今回は自前で用意したいのですが、。。
↓VBやC#ですけど考え方の参考にはなるのではないでしょうか。
http://dobon.net/vb/dotnet/string/detectcode.html
http://www.geocities.jp/gakaibon/tips/csharp2008/charset-check.html
…書かれている内容見れば分かると思いますが、自力判定って大変ですよ~。
VC系だと、COMインターフェイスの知識が必要ですが↓で簡単に検出できます。
IMultiLanguage2::DetectInputCodepage()
IEで文字化けしないものは大抵判別可能ですし、判別した文字コードでUNICODEにする
のも↓のメソッドで簡単に実現できるので、最近ではこういった変換を自力で行わなく
なってきたと思います。
IMultiLanguage2::ConvertStringToUnicode()
こういったものを独自で実装を行いたいということであれば、文字コードの特徴をじ
っくり読み込み、理解し、どういう優先度で判定していくかという設計を自力で行って
いくことになります。
あぁ、書いてる途中で・・・
皆さん書かれているとおりに、自力実装はかなりしんどいです。
検出精度を上げるには、さまざまなタイプのテキストを読み込ませて(数式が多いの
とか、カナが多いのとか、アルファベットが多いのとか・・・)どういった重み付けを
持たせて判定させるかという、利用シーンに合わせた判断が必要になるのです。
よって、正解がありませんので一般的な回答は得にくいと言えます。
自力実装を目指すのであれば、文字コード表をじっくり眺め、文字の分布、有効範
囲、有効文字、制御コード類、バイト数など、その特徴を抽出して行くという事が遠回
りに見えますが解決の糸口になると思います。
ARさん、ありがとうございます。
かなり楽に解決できそうです。
皆さんありがとうございました