UTF-8字符串迭代器

Qma*_*man 6 c++ string unicode iterator utf-8

我正在尝试编写支持Unicode的跨平台应用程序.我正在使用库UTF8-C++(http://utfcpp.sourceforge.net/)但我在迭代字符串时遇到问题:

string s1 = "?????? ????";
utf8::iterator<string::iterator> iter(s1.begin(), s1.begin(), s1.end());

for(int i = 0; i < utf8::distance(s1.begin(), s1.end()); i++, ++iter)
{
    cout << (*iter);
}
Run Code Online (Sandbox Code Playgroud)

上面的代码重定向到UTF-8格式的文本文件时,会产生以下输出:

6 3 6 3 6 3 6 3 6 3 6 3 3 2 6 3 6 3 6 3 6 3 
Run Code Online (Sandbox Code Playgroud)

如何才能s1正确显示文件中的内容?

bam*_*s53 9

您需要确保使用正确的数据初始化字符串,然后迭代器生成正确的值.

你正在使用VS2010,所以字符串文字有点问题.C++实现有一个'执行字符集',它们从'源字符集'转换字符和字符串文字.Visual Studio不支持UTF-8作为执行字符集,因此不会故意生成UTF-8编码的字符串文字.

你可以通过欺骗编译器或使用十六进制转义来获得一个.此外,您可以获取包含正确数据的宽字符串,然后在运行时将其转换为UTF-8,而不是获取UTF-8字符串文字.


编辑:Visual Studio的更新版本现在有办法获得UTF-8字符串文字.Visual Studio 2015现在支持C++ 11的UTF-8字符串文字.在Visual Studio 2015 Update 2中,您还可以使用编译器flags / execution-charset:utf-8或/ utf-8.


欺骗编译器

如果将源代码保存为"UTF-8 without signature",则编译器会认为源编码是系统区域设置编码.VS始终使用系统区域设置编码作为执行编码.因此,当它认为源和执行编码是相同的时,它将不执行任何转换,并且您的源字节(实际上将是UTF-8)将直接用于字符串文字,从而产生UTF-8编码的字符串文字.(请注意,这会破坏对宽字符和字符串文字的转换.)

十六进制逃脱

十六进制转义码允许您手动将任何值的代码单元(在本例中为字节)插入到字符串文字中.您可以手动确定所需的UTF-8编码,然后将这些值插入到字符串文字中.

std::string s1 = "\xd0\x94\xd0\xbe\xd0\xb1\xd1\x80\xd1\x8b\xd0\xb9 \xd0\xb4\xd0\xb5\xd0\xbd\xd1\x8c";
Run Code Online (Sandbox Code Playgroud)

UTF-8字符串文字前缀

C++ 11指定了一个前缀,无论执行编码如何,都会创建UTF-8字符串文字,但Visual Studio尚未实现此功能.这看起来像:

string s1 = u8"?????? ????";
Run Code Online (Sandbox Code Playgroud)

它要求编译器知道并使用正确的源编码(因此源编码支持所需的字符串).然后,编译器执行从源编码到UTF-8的转换,而不是执行编码.当Visual Studio支持此功能时,您可能希望将源代码保存为"带签名的UTF-8".(同样,VS依赖于签名来识别UTF-8源.)


在你有一个UTF-8字符串然后,假设UTF-8迭代器工作,你的示例代码应该产生正确的11个代码点,我认为输出文本应该如下所示:

104410861073108810991081321076107710851100
Run Code Online (Sandbox Code Playgroud)

插入一些空格以使其可读,您可以验证您是否获得了正确的值:

1044 1086 1073 1088 1099 1081 32 1076 1077 1085 1100
Run Code Online (Sandbox Code Playgroud)

或者将其设为十六进制并添加Unicode前缀:

U+0414 U+043e U+0431 U+0440 U+044b U+0439 U+0020 U+0434 U+0435 U+043d U+044c
Run Code Online (Sandbox Code Playgroud)

如果你真的想要生成一个UTF-8编码的输出文件,那么你不应该使用utf-8迭代器.

string s1 = "?????? ????";
std::cout << s1;
Run Code Online (Sandbox Code Playgroud)

当输出重定向到文件时,该文件将包含UTF-8编码数据:

?????? ????
Run Code Online (Sandbox Code Playgroud)

我不明白为什么你的实际输出目前包含一堆额外的空格,但它看起来像正在访问的实际数字是:

63 63 63 63 63 63 32 63 63 63 63
Run Code Online (Sandbox Code Playgroud)

63是'?'的ascii代码 32是空格的ascii代码; ?????? ????.所以你显然正在遭受VC++将字符串文字转换为系统语言环境编码的困扰.


Gar*_*son -1

答案已更新。使用wstring(我认为最好给VS2010)存储UTF16字符串,转换为UTF8,然后输出。

\n\n

当我在 UTF8 兼容编辑器 (Scite) 中查看时,这对我有用。

\n\n
    std::wstring s1 = L"\xd0\x94\xd0\xbe\xd0\xb1\xd1\x80\xd1\x8b\xd0\xb9 \xd0\xb4\xd0\xb5\xd0\xbd\xd1\x8c";\n    std::vector<unsigned char> UTF8;\n\n    utf8::utf16to8( s1.begin(), s1.end(), std::back_inserter( UTF8 ) );\n\n    for( auto It = UTF8.begin() ; It < UTF8.end() ; ++It )\n    {\n        std::cout << (*It);\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

我认为 VS2010 中没有办法拥有 UTF8 文字或字符串对象,UTF16(wstring)我认为是内部最好的选择,然后在导出到文件/时使用 UTF8 库在 UTF8 之间进行转换/网络等

\n

  • 宽字符串永远不会以 UTF8 格式存储,因此使用 UTF8 迭代器对其进行迭代没有多大意义。 (2认同)