如何获得 std::string 的准确长度?
Posted
技术标签:
【中文标题】如何获得 std::string 的准确长度?【英文标题】:How to get the accurate length of a std::string? 【发布时间】:2015-07-27 11:53:52 【问题描述】:我正在使用此代码修剪一个长 std::string
以将其放入文本容器中。
std::string AppDelegate::getTrimmedStringWithRange(std::string text, int range)
if (text.length() > range)
std::string str(text,0,range-3);
return str.append("...");
return text;
但是对于像HINDI "हिन्दी"
这样的其他语言,std::string
的长度是错误的。
我的问题是如何在所有测试用例中检索 std::string 的准确长度。
谢谢
【问题讨论】:
std::string
仅支持 ASCII。您可能需要std::wstring
或类似的数据结构
我可以将 std::string 更改为 std::wstring 吗?反之亦然?
是的,看到这个:***.com/questions/2573834/…
@AndyG: std::string
不支持任何特定的编码。它只存储字节。它完全能够存储非 ascii 字符串。例如 UTF-8。
@AndyG,我不知道那个字符串的确切长度,它看起来像“3”,如果你使用 wstring,长度是 6。正如 Benjamin Lindley 指出的那样,只有 std::string存储字节,内部表示取决于您的设置。
【参考方案1】:
假设您使用的是 UTF-8,您可以将字符串转换为简单的(哈哈!)Unicode 并计算字符数。我从rosettacode 获取了这个例子。
#include <iostream>
#include <codecvt>
int main()
std::string utf8 = "\x7a\xc3\x9f\xe6\xb0\xb4\xf0\x9d\x84\x8b"; // U+007a, U+00df, U+6c34, U+1d10b
std::cout << "Byte length: " << utf8.size() << '\n';
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> conv;
std::cout << "Character length: " << conv.from_bytes(utf8).size() << '\n';
【讨论】:
这将产生 Unicode 代码点中字符串的长度,但不会产生字符串的显示大小,因为一些 Unicode 字符的长度为零(特别是组合字符,如变音符号),而另一些则有长度两个在固定宽度的控制台上。 (如果输出不是固定宽度的字体,那么情况就完全不同了,很明显。)在 Posix 中,您可以使用wcswidth
,但这可能适用于 C++,也可能不适用于 C++。【参考方案2】:
std::string
的长度没有“错误”;你只是误解了它的意思。 std::string
以您选择的编码存储字节,而不是“字符”。它兴高采烈地不知道那一层。因此,std::string
的长度就是它包含的字节数。
要计算此类“字符”,您需要一个支持分析您选择的编码的库。
只有当您选择的编码与 ASCII 兼容时,您才能计算字节数并使用它。
【讨论】:
IIRC,有多种正确的方法来计算 Unicode 中的“字符”。对于每个,您可能想要计算“字素”而不是代码点。所以即使你坚持使用 UTF-8,你也需要考虑一下你想要计算什么样的东西。 (同样,据我所知,除了 UTF-8 方案,我真的知道的很少)【参考方案3】:如 cmets 中所述,长度将返回以utf8 编码的字符串的字节数。在这种多字节编码中,非 ascii 字符被编码为 2 到 6 个字节,因此您的 utf8 字符串长度会显得比 unicode 字母的实际数量更长。
解决方案 1
如果你有很多长字符串,你可以把它们保存在 utf8 中。 utf8 编码使得找出额外的多字节字符变得相对容易:它们都以二进制的 10xxxxxx 开头。所以计算这些额外字节的数量,并从字符串长度中减去它
cout << "Bytes: " << s.length() << endl;
cout << "Unicode length " << (s.length() - count_if(s.begin(), s.end(), [](char c)->bool return (c & 0xC0) == 0x80; )) << endl;
解决方案 2
如果需要更多处理而不仅仅是计算长度,您可以考虑在标准库中使用wstring_convert::from_bytes()
将您的字符串转换为 wstring。 wstring 的长度应该是您所期望的。
wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> cv;
wstring w = cv.from_bytes(s);
cout << "Unicode length " << w.length() << endl;
注意: linux上的wstring
是基于32位wchar_t
的,一个这样的宽字符可以包含所有的unicode字符集。所以这是完美的。然而,在 Windows 上,wchar_t
只有 16 位,因此某些字符可能仍需要多字编码。幸运的是,所有hindi characters 都在 U+0000 到 U+D7FF 的范围内,可以在一个 16 位字上进行编码。所以也应该没问题。
【讨论】:
你怎么知道是UTF-8? @LightnessRacesinOrbit 好问题。最佳猜测:它带有 cocos2d-x 标签,supported platforms 都符合 unicode 或 UCS16。在这种情况下,以 utf8 编码存储 unicode 似乎比其他多字节编码更有可能以上是关于如何获得 std::string 的准确长度?的主要内容,如果未能解决你的问题,请参考以下文章
C++ std::string::size()函数(返回字符串的长度,以字节为单位)(与std::string::length()函数相同)
根据缓冲区长度将空终止字符数组复制到 std::string