【发布时间】:2020-03-03 00:44:11
【问题描述】:
为什么某些 utf16 编码的宽字符串在转换为 utf8 编码的窄字符串时会转换为使用此常见转换函数转换时似乎不正确的十六进制值?
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 字符串获取,我正在使用上述函数将其转换为 utf8 窄字符串。
这个功能可以在网上的很多地方找到,几乎在所有情况下都可以使用。但是,我发现了一些似乎没有按预期工作的示例。
例如,如果我输入一个表情符号“????”作为字符串文字(在我的 utf8 编码的 cpp 文件中)并将其写入磁盘,文件 (FILE-1) 包含以下数据(它们是此处指定的正确 utf8 十六进制值https://www.fileformat.info/info/unicode/char/1f922/index.htm):
0xF0 0x9F 0xA4 0xA2
但是,如果我在命令行上将表情符号传递给我的应用程序,并使用上面的转换函数将其转换为 utf8 字符串,然后将其写入磁盘,则文件 (FILE-2) 包含不同的原始字节:
0xED 0xA0 0xBE 0xED 0xB4 0xA2
如果您复制并粘贴十六进制值(至少在 notepad++ 中),第二个文件似乎表明转换产生了错误的输出,但它会产生正确的表情符号。 WinMerge 也认为这两个文件是相同的。
所以总结一下,我真的很想知道以下几点:
- 在上面的示例中,看起来不正确的转换十六进制值如何正确映射到正确的 utf8 字符
- 为什么转换函数将某些字符转换为这种形式,而几乎所有其他字符都生成预期的原始字节
- 作为奖励,我想知道是否可以修改转换函数以阻止它以这种形式输出这些稀有字符
我应该注意到我已经有一个使用 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;
}
【问题讨论】:
标签: c++ string unicode utf-8 character-encoding