给出一个字符串std::string str = "google谷歌"
,遍历它并打印每个字符:
for (uint32 i = 0; i <= str.length(); ++i)
std::cout << str[i] << std::endl;
,打印:
g
o
o
g
l
e
�
�
�
�
�
�
这显然是错误的,我改为使用std::wstring
:
for (uint32 i = 0; i <= str.length(); ++i)
std::cout << str[i] << std::endl;
,打印:
103
111
111
103
108
101
35895
27468
0
以上是每个字符的原始整数数据,这是正确的。我可以使用utf8cpp
库将它们转换为utf8并正确打印。
问题是:有没有简单的方法可以使用可变长度字符遍历std::string
而不使用std::wstring
?
我这里也有一些丑陋的代码:
bool Utf8toWStr(const std::string& utf8str, std::wstring& wstr)
{
size_t len = utf8::distance(utf8str.c_str(), utf8str.c_str() + utf8str.size());
wstr.resize(len);
if (len)
utf8::utf8to16(utf8str.c_str(), utf8str.c_str() + utf8str.size(), &wstr[0]);
return true;
}
bool WStrToUtf8(std::wstring wstr, std::string& utf8str)
{
std::string utf8str2;
utf8str2.resize(wstr.size() * 4); // allocate for most long case
char* oend = utf8::utf16to8(wstr.c_str(), wstr.c_str() + wstr.size(), &utf8str2[0]);
utf8str2.resize(oend - (&utf8str2[0])); // remove unused tail
utf8str = utf8str2;
return true;
}
std::string m_text;
std::wstring textWStr;
Utf8toWStr(m_text, textWStr);
auto textLen = textWStr.length();
for (uint32 1 = 1; i <= textLen; ++i)
{
std::wstring subWStr = textWStr.substr(0, i);
std::string subStr;
WStrToUtf8(subWStr, subStr);
std::cout << "subStr = " << subStr << std::endl;
}
答案 0 :(得分:2)
除了与损坏的库(例如,Windows API)接口外,不要使用std::wstring
和朋友。他们只会让问题变得更糟。 UTF16仍然是可变宽度编码。
正确的解决方案是在所有地方使用UTF8,如here所述。
在UTF8字符串中迭代'characters',其中'character'是代码点或字形集群,不是标准库的一个功能。 ICU是完成该任务的相当普遍的选择。如果您只想输出字符串,只需将整个字符串提供给std::cout
,该字符串应正确处理UTF8。如果你遇到了Windows,请使用一个包装器转发到标准库中的std::cout
,然后将转换后的std::string
转发给std::wcout
。