日本語文字コード判定、ICUを使ってみた。

文字コードの自動判定について調べていたらコチラの記事を見つけました。
日本語文字コード認識のテストレポートらしい - てきとうなメモ

libguess 0.99971(5個)、 ICU 0.9996(6個)、 nkf 0.998567(25個)、 universalchardet 0.969221(537個)

日本語限定であればlibguess。 世界各国語が対象なら判定速度は遅いがICUがいい。

なるほど。ということで、ICUを使ったコードを書いてみました。

unicode/ucsdet.hをincludeしてやって、

#include <unicode/ucsdet.h>

こんな感じのコードで、判定できるようです。このコードでは、一致した文字コードを10個まで表示しています。

    …

    UErrorCode error = U_ZERO_ERROR;
    UCharsetDetector* detector = ucsdet_open(&error);
    if (U_FAILURE(error))
        return NULL;

    ucsdet_setText(detector, s.c_str(), s.size(), &error);
    if (U_FAILURE(error))
        return NULL;

    int32_t founded = 0;
    const UCharsetMatch** matchers =
        ucsdet_detectAll(detector, &founded, &error);

    if (U_FAILURE(error))
        return NULL;

    if (founded > 0) {
        const int32_t kThresold = 10;
        for (int i = 0; i < founded; ++i) {
            int32_t confidence = ucsdet_getConfidence(matchers[i], &error);
            if (U_FAILURE(error)) {
                error = U_ZERO_ERROR;
                continue;
            }
            if (confidence < kThresold)
                break;
            const char* match_encoding = ucsdet_getName(matchers[i], &error);
            if (U_FAILURE(error)) {
                error = U_ZERO_ERROR;
                continue;
            }
            const char* match_lang = ucsdet_getLanguage(matchers[i], &error);
            if (U_FAILURE(error)) {
                error = U_ZERO_ERROR;
                continue;
            }

            std::cout << "     neme:" << match_encoding
                      << " language:" << match_lang
                      << std::endl;
        }
        std::cout << "-----" << std::endl;
    }

    ucsdet_close(detector);

    …

ucsdet_detectAllを使用して、文字コード判定を行えます。
また、判定コードがひとつだけでいい場合は、ucsdet_detectを使えば良いようです。

    const UCharsetMatch* match = ucsdet_detect(detector, &error);
    if (U_FAILURE(error))
        return NULL;
    std::cout << "     neme:" << ucsdet_getName(match, &error)
              << " language:" << ucsdet_getLanguage(match, &error)
              << std::endl;