5

ユニコードをサポートする端末ベースのプログラムに取り組んでいます。文字列を印刷する前に、文字列が消費する端末列の数を決定する必要がある場合があります。残念ながら、一部の文字は 2 列幅 (中国語など) ですが、ICU ライブラリから u_getIntPropertyValue() を呼び出すことで、全角文字を検出する良い方法を示すこの回答が見つかりました。

今、UTF8 文字列の文字を解析して、この関数に渡そうとしています。私が今抱えている問題は、u_getIntPropertyValue() が UTF-32 コード ポイントを想定していることです。

これをutf8文字列から取得する最良の方法は何ですか? 現在、boost::locale (プログラムの他の場所で使用) を使用してこれを実行しようとしていますが、クリーンな変換を行うのに問題があります。boost::locale からの UTF32 文字列は、バイト順を示すために幅ゼロの文字が先頭に追加されます。明らかに、文字列の最初の 4 バイトをスキップできますが、これを行うよりクリーンな方法はありますか?

これが私の現在の醜い解決策です:

inline size_t utf8PrintableSize(const std::string &str, std::locale loc)
{
    namespace ba = boost::locale::boundary;
    ba::ssegment_index map(ba::character, str.begin(), str.end(), loc);
    size_t widthCount = 0;
    for (ba::ssegment_index::iterator it = map.begin(); it != map.end(); ++it)
    {
        ++widthCount;
        std::string utf32Char = boost::locale::conv::from_utf(it->str(), std::string("utf-32"));

        UChar32 utf32Codepoint = 0;
        memcpy(&utf32Codepoint, utf32Char.c_str()+4, sizeof(UChar32));

        int width = u_getIntPropertyValue(utf32Codepoint, UCHAR_EAST_ASIAN_WIDTH);
        if ((width == U_EA_FULLWIDTH) || (width == U_EA_WIDE))
        {
            ++widthCount;
        }

    }
    return widthCount;
}
4

2 に答える 2

1

UTF-32 は、個々の文字の「コード ポイント」を直接表現したものです。したがって、UTF-8 文字からそれらを抽出し、これを にフィードするだけu_getIntPropertyValueです。

私はあなたのコードを取得し、 u8_to_u32_iteratorを使用するように変更しました。これは、このためだけに作成されたようです:

#include <boost/regex/pending/unicode_iterator.hpp>

inline size_t utf8PrintableSize(const std::string &str, std::locale loc)
{
    size_t widthCount = 0;
    for(boost::u8_to_u32_iterator<std::string::iterator> it(input.begin()), end(input.end()); it!=end; ++it)
    {
        ++widthCount;

        int width = u_getIntPropertyValue(*it, UCHAR_EAST_ASIAN_WIDTH);
        if ((width == U_EA_FULLWIDTH) || (width == U_EA_WIDE))
        {
            ++widthCount;
        }

    }
    return widthCount;
}
于 2016-05-23T19:10:20.797 に答える