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

标签 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;
}

最佳答案

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

知道是UTF-8,就可以统计一下Unicode码位的个数。您可以使用作为代码点的 u32string。我不相信 C++ 有直接在开箱即用的 u8string 上这样做的功能:

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

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

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

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

关于c++ - 如何在 C++ 中获得 std::u8string 的正确长度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59691715/

相关文章:

java - 将数值添加到字符串名称的最简单方法

c# - 如何在字符串中的条件运算符前后添加空格?

c++ - QFileDialog unicode目录不可用

winapi - 如何在编码之间获得最适合的 unicode 字符映射

unicode - PhantomJS 无法识别特殊/重音 UTF-8 字符

c++ - std::cout 中的递归打印

c++ - Cusparse 非法内存访问,除非我增加稀疏矩阵的稀疏性

c - 查找字符串中字符串分隔符的数量

c++ - 防止同一个宏在多个翻译单元中有不同的定义

c++ - 是否允许标准库算法复制谓词参数?