文字コード判定処理

[戻る]
AVAILABLE 2011/09/11(日) 11:51:45
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が高くなります
どういうことでしょうか

tetrapod 2011/09/12(月) 09:37:44
このような目的のためには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 での保存は禁止している)

AVAILABLE 2011/09/12(月) 16:38:09
短文の場合に判断ミスが出てしまうのは仕方ないと思います。ここでは考えないことにし
ました。

>このような目的のためには1バイト(1オクテット)単位でのチェックでは不足で
>連続するバイト(オクテット)の組み合わせによる妥当性を考察する必要がある。

となるとどのような処理を行うべきでしょうか?

現在考えているのは
8bit目がなくてエスケープシーケンスがある→ISO2022JP
何らかの方法でUTF16を判定する
UTF-8の判定は、Wikipedia UTF-8 で何とかなりそうです。
Shift-JISとEUCJPを何らかの方法で判別する



UTF16についてはずっと困っています。
また、SJISとEUCJPもわかりません

tetrapod 2011/09/12(月) 19:53:43
この辺、自作するのは開発コストの問題で割に合わないと思うのだが・・・
自作しなきゃならない理由が何かある、のなら別だが、
俺なら libiconv とか IBM ICU とか既存のライブラリを使う。
変換元に *** を指定して、変換できたらその encoding が使われている、とするだけ。

sjis ってあっさり言ってるけど 本当に狭義の sjis を使いたいの?
本当は Windows-31j ないしは cp932 ではないの?
euc は euc-jp だけでいいの? euc-cn, euc-kr とか考えなくていいの?
などなど言い始めるとますますもって自作したくないんだが。

AVAILABLE 2011/09/13(火) 18:13:19
SJISとは今回はcp932を指します
また、eucはjpだけでいいです。

iconvの使用ですが、インストールが必要みたいなのですが、どういうことなのでしょうか?
IBM ICUはUNICODEのみなのでやめておきます

また、iconv,ICUともにLinux用の解説しかないのでよく分かりません。

今回は自前で用意したいのですが、。。

みい 2011/09/13(火) 22:05:47
↓VBやC#ですけど考え方の参考にはなるのではないでしょうか。
http://dobon.net/vb/dotnet/string/detectcode.html
http://www.geocities.jp/gakaibon/tips/csharp2008/charset-check.html

…書かれている内容見れば分かると思いますが、自力判定って大変ですよ〜。

AR 2011/09/14(水) 01:21:09
 VC系だと、COMインターフェイスの知識が必要ですが↓で簡単に検出できます。
 IMultiLanguage2::DetectInputCodepage()

 IEで文字化けしないものは大抵判別可能ですし、判別した文字コードでUNICODEにする
のも↓のメソッドで簡単に実現できるので、最近ではこういった変換を自力で行わなく
なってきたと思います。
 IMultiLanguage2::ConvertStringToUnicode()

 こういったものを独自で実装を行いたいということであれば、文字コードの特徴をじ
っくり読み込み、理解し、どういう優先度で判定していくかという設計を自力で行って
いくことになります。

AR 2011/09/14(水) 01:34:10
 あぁ、書いてる途中で・・・
 皆さん書かれているとおりに、自力実装はかなりしんどいです。

 検出精度を上げるには、さまざまなタイプのテキストを読み込ませて(数式が多いの
とか、カナが多いのとか、アルファベットが多いのとか・・・)どういった重み付けを
持たせて判定させるかという、利用シーンに合わせた判断が必要になるのです。
 よって、正解がありませんので一般的な回答は得にくいと言えます。

 自力実装を目指すのであれば、文字コード表をじっくり眺め、文字の分布、有効範
囲、有効文字、制御コード類、バイト数など、その特徴を抽出して行くという事が遠回
りに見えますが解決の糸口になると思います。

AVAILABLE 2011/09/15(木) 19:11:09
[[解決]]
ARさん、ありがとうございます。
かなり楽に解決できそうです。

皆さんありがとうございました

古いスレッドには追加発言できません。