代码之家  ›  专栏  ›  技术社区  ›  ryancheung

使用可变长度字符遍历std::字符串的更好方法?

c++
  •  2
  • ryancheung  · 技术社区  · 8 年前

    给出字符串 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 :

    对于(uint32 i=0;i<=str.length()++(一)
    标准::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 回复  |  直到 8 年前
        1
  •  2
  •   James Picone    8 年前

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

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

    在UTF8字符串中迭代“characters”(其中“character”是代码点或grapheme集群),这不是标准库的功能。 ICU 对于该任务来说是一个相当常见的选择。如果只想输出字符串,只需将整个字符串馈送到 std::cout ,应能正确处理UTF8。如果您一直使用Windows,请使用一个 标准::cout 在良好的标准库中,并转发转换的 std::string 到 std::wcout 在坏的方面。