使用可变长度字符遍历std :: string的更好方法是什么?

时间:2018-04-04 03:54:20

标签: c++

给出一个字符串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;
}

1 个答案:

答案 0 :(得分:2)

除了与损坏的库(例如,Windows API)接口外,不要使用std::wstring和朋友。他们只会让问题变得更糟。 UTF16仍然是可变宽度编码。

正确的解决方案是在所有地方使用UTF8,如here所述。

在UTF8字符串中迭代'characters',其中'character'是代码点或字形集群,不是标准库的一个功能。 ICU是完成该任务的相当普遍的选择。如果您只想输出字符串,只需将整个字符串提供给std::cout,该字符串应正确处理UTF8。如果你遇到了Windows,请使用一个包装器转发到标准库中的std::cout,然后将转换后的std::string转发给std::wcout