如何获取std::string的准确长度?
How to get the accurate length of a std::string?
我正在修剪一个长 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
的长度不是"wrong";你只是误解了它的意思。 std::string
存储字节,而不是您选择的编码中的 "characters"。它兴高采烈地不知道那一层。因此,std::string
的长度就是它包含的字节数。
要计算此类 "characters",您需要一个支持分析您选择的编码的库,无论是什么。
只有当您选择的编码与 ASCII 兼容时,您才能只计算字节数并完成它。
假设您使用的是 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';
}
如评论中所述,长度将 return 以 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;
注意: wstring
on linux是基于32位wchar_t
和一个这样宽的字符可以包含所有的 unicode 字符集。所以这是完美的。然而,在 windows 上,wchar_t
只有 16 位,因此某些字符可能仍需要多字编码。幸运的是,所有 hindi characters 都在 U+0000 到 U+D7FF 的范围内,可以编码为一个 16 位字。所以应该也可以。
我正在修剪一个长 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
的长度不是"wrong";你只是误解了它的意思。 std::string
存储字节,而不是您选择的编码中的 "characters"。它兴高采烈地不知道那一层。因此,std::string
的长度就是它包含的字节数。
要计算此类 "characters",您需要一个支持分析您选择的编码的库,无论是什么。
只有当您选择的编码与 ASCII 兼容时,您才能只计算字节数并完成它。
假设您使用的是 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';
}
如评论中所述,长度将 return 以 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;
注意: wstring
on linux是基于32位wchar_t
和一个这样宽的字符可以包含所有的 unicode 字符集。所以这是完美的。然而,在 windows 上,wchar_t
只有 16 位,因此某些字符可能仍需要多字编码。幸运的是,所有 hindi characters 都在 U+0000 到 U+D7FF 的范围内,可以编码为一个 16 位字。所以应该也可以。