TL;DR
basic_string 的size() 和length() 成员返回基础字符串的单位 大小,不是 的数量可见字符。要获得预期的数字:
" ██████" 是一个空格,后跟一系列 6 个U+2588 字符。您的编译器似乎将UTF-8 用于std::string。 UTF-8 是variable-length encoding 并且许多字母使用多个字节进行编码(因为显然你不能仅用一个字节编码超过 256 个字符)。在 U+0800 和 U+FFFF 之间的 UTF-8 代码点由 3 个字节编码。因此 UTF-8 中字符串的长度为 1 + 6*3 = 19 个字节。
您可以使用任何 Unicode 转换器(如 this one)检查字符串是否以 UTF-8 编码为 20 E2 96 88 E2 96 88 E2 96 88 E2 96 88 E2 96 88 E2 96 88,您还可以遍历字符串的每个字节进行检查
如果你想要字符串中的可见个字符的总数,那么这会很棘手,并且 churill 的解决方案不起作用。阅读Twitter中的示例
如果您使用最基本的字母、数字和标点符号之外的任何内容,情况会变得更加混乱。虽然许多人使用多字节汉字来举例说明这些问题,但 Twitter 发现重音元音会引起最大的混乱,因为说英语的人只是希望它们能正常工作。举个例子:“咖啡馆”这个词。事实证明,有两个字节序列看起来完全相同,但使用的字节数不同:
café 0x63 0x61 0x66 0xC3 0xA9 Using the “é” character, called the “composed character”.
café 0x63 0x61 0x66 0x65 0xCC 0x81 Using the combining diacritical, which overlaps the “e”
您需要一个 Unicode 库,例如 ICU 到 normalize 的字符串和计数。例如 Twitter 使用 Normalization Form C
编辑:
由于您只对似乎不在 BMP 之外且不包含任何组合字符的方框图字符感兴趣,因此 UTF-16 和 UTF-32 可以工作。与std::string 一样,std::wstring 也是basic_string,并且没有强制编码。在大多数实现中,它通常是 UTF-16 (Windows) 或 UTF-16 (*nix),因此您可以使用它,但它不可靠并且取决于源代码编码。更好的方法是使用std::u16string (std::basic_string<char16_t>) 和std::u32string (std::basic_string<char32_t>)。无论源文件的系统和编码如何,它们都可以工作
std::wstring wstr = L" ██████";
std::u16string u16str = u" ██████";
std::u32string u32str = U" ██████";
std::cout << str.size(); // may work, returns the number of wchar_t characters
std::cout << u16str.size(); // always returns the number of UTF-16 code units
std::cout << u32str.size(); // always returns the number of UTF-32 code units
如果您对如何解决所有 Unicode 字符感兴趣,请继续阅读下文
上面提到的“café”问题引发了一个问题,即如何计算 Tweet 字符串“café”中的字符数。对人眼来说,长度显然是四个字符。根据数据的表示方式,这可能是五个或六个 UTF-8 字节。 Twitter 不想因为我们使用 UTF-8 或所讨论的 API 客户端使用更长的表示这一事实而惩罚用户。因此,无论发送哪种表示形式,Twitter 都将“café”计为四个字符。
[...]
Twitter 使用文本的规范化表格 C (NFC) 版本计算推文的长度。这种类型的规范化有利于使用完全组合的字符(咖啡馆示例中的 0xC3 0xA9)而不是长格式版本(0x65 0xCC 0x81)。 Twitter 还计算文本中的代码点数,而不是 UTF-8 字节数。咖啡馆示例中的 0xC3 0xA9 是一个代码点 (U+00E9),在 UTF-8 中编码为两个字节,而 0x65 0xCC 0x81 是两个代码点,编码为三个字节
Twitter - Counting characters
另见