Unicode字符串的跨平台迭代(使用ICU计算字母)

kiz*_*zx2 20 c++ unicode cross-platform icu

我想迭代Unicode字符串的每个字符,处理每个代理对并将字符序列组合为一个单元(一个字形).

文本"नमस्ते"由代码点组成:U+0928, U+092E, U+0938, U+094D, U+0924, U+0947其中,U+0938并且U+0947组合标记.

static void Main(string[] args)
{
    const string s = "??????";

    Console.WriteLine(s.Length); // Ouptuts "6"

    var l = 0;
    var e = System.Globalization.StringInfo.GetTextElementEnumerator(s);
    while(e.MoveNext()) l++;
    Console.WriteLine(l); // Outputs "4"
}
Run Code Online (Sandbox Code Playgroud)

所以我们在.NET中有它.我们也有Win32的CharNextW()

#include <Windows.h>
#include <iostream>
#include <string>

int main()
{
    const wchar_t * s = L"??????";

    std::cout << std::wstring(s).length() << std::endl; // Gives "6"

    int l = 0;
    while(CharNextW(s) != s)
    {
        s = CharNextW(s);
        ++l;
    }

    std::cout << l << std::endl; // Gives "4"

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我所知道的两种方式都是微软特有的.有可移植的方法吗?

  • 我听说过ICU,但我找不到快速相关的东西(UnicodeString(s).length()仍然给出6).指向ICU中的相关功能/模块是一个可接受的答案.
  • C++没有Unicode的概念,因此用于处理这些问题的轻量级跨平台库将成为可接受的答案.

编辑:使用ICU正确回答

@McDowell提供了使用BreakIteratorICU 的提示,我认为这可以被视为处理Unicode的事实上的跨平台标准.这是一个示例代码来演示它的用法(因为示例 非常罕见):

#include <unicode/schriter.h>
#include <unicode/brkiter.h>

#include <iostream>
#include <cassert>
#include <memory>

int main()
{
    const UnicodeString str(L"??????");

    {
        // StringCharacterIterator doesn't seem to recognize graphemes
        StringCharacterIterator iter(str);
        int count = 0;
        while(iter.hasNext())
        {
            ++count;
            iter.next();
        }
        std::cout << count << std::endl; // Gives "6"
    }

    {
        // BreakIterator works!!
        UErrorCode err = U_ZERO_ERROR;
        std::unique_ptr<BreakIterator> iter(
            BreakIterator::createCharacterInstance(Locale::getDefault(), err));
        assert(U_SUCCESS(err));
        iter->setText(str);

        int count = 0;
        while(iter->next() != BreakIterator::DONE) ++count;
        std::cout << count << std::endl; // Gives "4"
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

McD*_*ell 13

您应该能够使用ICU BreakIterator(假设它的特征等同于Java版本的字符实例).