如何在 C++ 中获得 std::u8string 的正确长度?

KiY*_*ter 2 c++ string unicode c++20

如何获得 std::u8string 的正确长度?(在 C++20 中)我尝试了以下代码,这些代码打印了错误的长度值,这可能会返回代码点数量的值。

我怎样才能得到我期望的 7 个字符的正确值?

int main() {
    const char8_t* s = u8"Hello";
    auto st = std::u8string(s);
    std::cout << st.size() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

Fir*_*cer 7

u8string就大多数 C++ 函数而言,A实际上是一个字节序列。这样size()你就得到了 13 ( 48 65 6c 6c 6f f0 9f 98 83 f0 9f 98 83)。“”(“张开嘴的微笑脸”U+1F603)被编码为 4 个元素f0 9f 98 83[i]您也会通过、substr等看到这一点。

\n\n

知道是UTF-8,就可以统计Unicode码点的数量了。您可以使用u32stringis 代码点。我不相信 C++ 有直接开箱即用的函数u8string

\n\n
size_t count_codepoints(const std::u8string &str)\n{\n    size_t count = 0;\n    for (auto &c : str)\n        if ((c & 0b1100\'0000) != 0b1000\'0000) // Not a trailing byte\n            ++count;\n    return count;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然而,这可能仍然不是人们所认为的“字符数”。这是因为多个代码点可能用于表示单个可见字符,即“组合字符”。其中一些还具有“预组合”形式,并且组合代码点的顺序可能会有所不同,从而导致“正常形式”和比较 Unicode 字符串的问题。例如“\xc3\x81”可能是“LATIN CAPITAL LETTER A WITH ACUTE\' (U+00C1)”,即 UTF-8 C3 81,或者它可能有一个普通的“A”和“COMBINING ACUTE ACCENT (U+0301) )" 这是两个代码点和 3 个 UTF-8 字节41 CC 81

\n\n

unicode.org上有针对每个 Unicode 版本的表格,可让您正确处理和转换组合字符(以及大写/小写转换等内容),但它们非常广泛,您需要编写一些代码来处理它们。3rd 方库(我认为 Linux 主要使用 ICU)或操作系统功能(Window 有一堆 API)也提供各种实用程序。

\n\n

值得注意的是,您可能会在许多其他情况/语言中遇到这些问题,而不仅仅是 C++。例如,JavaScript、Java 和 .NET 以及 Windows C/C++ API(主要wchar_t在 Windows 上)使用 UTF-16 字符串,该字符串对某些代码点具有“代理对”,其中许多函数实际上计算 UTF-16 元素,而不是代码点。

\n