[英]Issue when converting utf16 wide std::wstring to utf8 narrow std::string for rare characters
为什么某些 utf16 编码的宽字符串在转换为 utf8 编码的窄字符串时会转换为使用此常见转换 function 进行转换时似乎不正确的十六进制值?
std::string convert_string(const std::wstring& str)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
return conv.to_bytes(str);
}
你好。 我在 Windows 上有一个 C++ 应用程序,它在命令行上需要一些用户输入。 我使用宽字符主入口点将输入作为 utf16 字符串,我使用上面的 function 将其转换为 utf8 窄字符串。
这个 function 可以在网上的很多地方找到,并且几乎在所有情况下都可以使用。 然而,我发现了一些似乎没有按预期工作的例子。
例如,如果我输入一个 emojii 字符 "" 作为字符串文字(在我的 utf8 编码 cpp 文件中)并将其写入磁盘,则文件 (FILE-1) 包含以下数据(这是此处指定的正确 utf8 十六进制值https ://www.fileformat.info/info/unicode/char/1f922/index.htm ):
0xF0 0x9F 0xA4 0xA2
但是,如果我在命令行上将表情符号传递给我的应用程序,并使用上面的转换 function 将其转换为 utf8 字符串,然后将其写入磁盘,则文件 (FILE-2) 包含不同的原始字节:
0xED 0xA0 0xBE 0xED 0xB4 0xA2
虽然第二个文件似乎表明转换产生了错误的 output 如果您复制并粘贴十六进制值(至少在记事本++中)它会产生正确的表情符号。 WinMerge 还认为这两个文件是相同的。
所以总结一下,我真的很想知道以下内容:
我应该注意到我已经有一个解决方法 function 下面使用 WinAPI 调用,但是只使用标准库调用是梦想:)
std::string convert_string(const std::wstring& wstr)
{
if(wstr.empty())
return std::string();
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
std::string strTo(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
return strTo;
}
问题是std::wstring_convert<std::codecvt_utf8<wchar_t>>
从 UCS-2 转换,而不是从 UTF-16转换。 BMP (U+0000..U+FFFF) 内部的字符在 UCS-2 和 UTF-16 中具有相同的编码,因此可以使用,但 BMP 之外的字符 (U+FFFF..U+10FFFF),例如作为您的表情符号,UCS-2 中根本不存在。 这意味着转换不理解字符并产生不正确的 UTF-8 字节(从技术上讲,它会将 UTF-16 代理对的每一半转换为单独的 UTF-8 字符)。
您需要改用std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>
。
这里已经有一个经过验证的答案。 但是为了记录,这里有一些额外的信息。
2016年的Unicode中引入了恶心的表情符号的 编码。它是4个utf-8字节( 0xF0 0x9F 0xA4 0xA2
)或2个utf-16字( 0xD83E 0xDD22
)
0xED 0xA0 0xBE 0xED 0xB4 0xA2
令人惊讶的编码实际上对应于 UCS 代理对:
所以基本上,你的第一个编码是直接的 utf8。 第二种编码是 UCS-2 编码的 utf8 编码,对应于所需字符的 utf-16 编码。
正如公认的答案正确指出的那样, std::codecvt_utf8<wchar_t>
是罪魁祸首,因为它是关于 UCS-2 而不是 UTF-16。
现在在标准库中找到这种过时的编码是相当令人惊讶的,但我怀疑这仍然是微软在标准委员会中游说的一种回忆,该标准委员会可以追溯到旧的 Windows 对带有 UCS-2 的 unicode 的支持。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.