potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

C++&Win32 API ICU4Cでユニコードを扱う

Windows 10 バージョン 1903以降、最新のSDKではicu.hicu.libicu.dllからICU4Cを使用できます。ICU4Cを使えばUnicode関係の詳細な処理が可能です。ここでは動作確認用のコードを公開します。

参考

この投稿を書く際に参照したページです。

ある文字の名前を取得する

u_charName関数を使用します。バッファーは自前で確保する必要があります。

#include <array>
#include <string>

#include <icu.h>
#pragma comment(lib, "icu.lib")

int wmain()
{
    UErrorCode status{ U_ZERO_ERROR };

    u_init(&status);

    std::array<char, 100> buffer;
    auto copied = u_charName(U'🍊', UCharNameChoice::U_UNICODE_CHAR_NAME, buffer.data(), std::size(buffer), &status);
    std::string char_name(buffer.cbegin(), buffer.cbegin() + copied);
    // "TANGERINE"

    return 0;
}

ある文字範囲の名前を取得する

u_enumCharNames関数を使用します。コールバック関数に順次コードや名前が渡されます。

#include <vector>
#include <string>
#include <tuple>

#include <icu.h>
#pragma comment(lib, "icu.lib")

int wmain()
{
    UErrorCode status{ U_ZERO_ERROR };

    u_init(&status);

    std::vector<std::tuple<UChar32, std::string>> names;
    u_enumCharNames(U'🍊', U'🍎' + 1, [](void* context, UChar32 code, UCharNameChoice nameChoice, const char* name, int32_t length) -> UBool
        {
            auto& names = *reinterpret_cast<std::vector<std::tuple<UChar32, std::string>>*>(context);
            names.emplace_back(std::make_tuple(code, name));
            return TRUE;
        },
        &names, UCharNameChoice::U_UNICODE_CHAR_NAME, &status);
    // [0] (127818, "TANGERINE")
    // [1] (127819, "LEMON")
    // [2] (127820, "BANANA")
    // [3] (127821, "PINEAPPLE")
    // [4] (127822, "RED APPLE")

    return 0;
}

文字の名前から文字コードを取得する

u_charFromName関数を使用します。

#include <string>

#include <icu.h>
#pragma comment(lib, "icu.lib")

int wmain()
{
    UErrorCode status{ U_ZERO_ERROR };

    u_init(&status);

    auto c = u_charFromName(UCharNameChoice::U_UNICODE_CHAR_NAME, "TANGERINE", &status);
    // 127818

    return 0;
}

ICUのバージョン情報を取得する

バイナリ形式はu_getDataVersion関数、バイナリ形式から文字列への変換はu_versionToString関数を使います。区切り文字はU_VERSION_DELIMITERとして定義されています。

#include <array>
#include <string>

#include <icu.h>
#pragma comment(lib, "icu.lib")

int wmain()
{
    // ICU4Cの初期化
    UErrorCode status{ U_ZERO_ERROR };
    u_init(&status);

    // バイナリ形式のバージョン情報取得
    UVersionInfo version{};
    u_getDataVersion(version, &status);
    // {64, 2, 0, 0}

    // 文字列形式のバージョン情報取得
    std::array<char, U_MAX_VERSION_STRING_LENGTH> versionString;
    u_versionToString(version, versionString.data());
    // 64.2

    // 文字列形式のバージョン情報の区切り文字
    auto delimiter = U_VERSION_DELIMITER;

    return 0;
}