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

C++ 使用可变长度字符遍历std::string的更好方法?,c++,C++,给出一个字符串std::string str=“google”谷歌",遍历它并打印每个字符: for (uint32 i = 0; i <= str.length(); ++i) std::cout << str[i] << std::endl; for (uint32 i = 0; i <= str.length(); ++i) std::cout << str[i] << std::endl; 这显然是错误的,我

给出一个字符串
std::string str=“google”谷歌",遍历它并打印每个字符:

for (uint32 i = 0; i <= str.length(); ++i)
    std::cout << str[i] << std::endl;
for (uint32 i = 0; i <= str.length(); ++i)
    std::cout << str[i] << std::endl;
这显然是错误的,我改为使用
std::wstring

上面是每个字符的原始整数数据,它们是正确的。我可以使用
utf8cpp
库将它们转换为utf8并正确打印

问题是:是否有任何简单的方法可以在不使用
std::wstring
的情况下使用可变长度字符遍历
std::string

我这里也有一些难看的代码:

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;
}
bool Utf8toWStr(常量std::string和utf8str,std::wstring和wstr)
{
距离(utf8str.c_str(),utf8str.c_str()+utf8str.size());
wstr.resize(len);
如果(len)
utf8::utf8to16(utf8str.c_str()、utf8str.c_str()+utf8str.size()、和wstr[0]);
返回true;
}
bool wstrutf8(std::wstring wstr、std::string和utf8str)
{
std::字符串utf8str2;
utf8str2.resize(wstr.size()*4);//为最长的情况分配
char*oend=utf8::utf16to8(wstr.c_str(),wstr.c_str()+wstr.size(),&utf8str2[0]);
调整大小(oend-(&utf8str2[0]);//删除未使用的尾部
utf8str=utf8str2;
返回true;
}
std::字符串m_文本;
std::wstring textWStr;
Utf8toWStr(m_text,textWStr);
auto textLen=textWStr.length();

对于(uint32 1=1;i不要使用
std::wstring
和friends,除了与坏库(例如Windows API)进行接口外。它们只会使问题变得更糟。UTF16仍然是一种可变宽度编码

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


迭代UTF8字符串中的“字符”,其中“字符”是代码点或图形集簇,这不是标准库的功能。这是该任务的一个相当常见的选择。如果您只想输出字符串,只需将整个字符串馈送到
std::cout
,该字符串应能正确处理UTF8。如果您一直使用Windows,在好的标准库中使用一个转发到
std::cout
的包装器,在坏的标准库中使用一个转换后的
std::string
转发到
std::wcout

打印“每个字符”…什么是字符?它是一个字形集群吗?(顺便说一句,永远不要使用wstring或wchar\t–它们与Windows上的string/char有着相同的问题,还有一些问题。)不确定,但我认为
是一个字符,也是
g
@Ry,所以最终的方法是使用Boost.Text,就像Henri Menke指出的那样?请注意utf16也是一种可变宽度编码!!!使用
wchar\U t
并不能避免将例如“POO堆”(U+1F4A9)一分为二:(我还想使用子字符串,就像我放的难看的代码一样。与Boost.Text(建议使用)相比,ICU似乎有点复杂。获取子字符串还需要一些编码感知的东西(比如ICU)。您链接到的Boost.Text库也可以工作;我只想指出,它没有ICU那么成熟,实际上还不是Boost库。文档声称具有必要的操作。
cout
的有趣部分。我认为为utf-8设置的终端将显示字节流的适当标志符号,而没有任何以前的处理,不是吗?标准C++流会做什么?如果我把它输出到<代码> String Strue,结果是什么?不同的字符串?@彼得拉·施奈德:它是实现定义的行为,标准库提供了VisualStudio处理<代码> STD::CUT< /COD>显示一些ANSI代码页。类似地,没有一种标准的方法来打开文件,文件名不能在VisualStudio的C++标准库中以ANSI代码页表示(尽管<代码> STD::文件系统< /Cord>支持可能会改变这一点)。
103
111
111
103
108
101
35895
27468
0
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;
}