我正在玩下面提到的代码: https://stackoverflow.com/a/21575607/2416394因为我在使用TinyXML编写正确的utf8 xml时遇到了问题。
好吧,我需要编写“带有DIAERESIS的LATIN CAPITAL LETTER U”,Ü
可以正确写入XML等。
以下是上述帖子中的代码:
std::string codepage_str = "Ü";
int size = MultiByteToWideChar( CP_ACP, MB_COMPOSITE, codepage_str.c_str(),
codepage_str.length(), nullptr, 0 );
std::wstring utf16_str( size, '\0' );
MultiByteToWideChar( CP_ACP, MB_COMPOSITE, codepage_str.c_str(),
codepage_str.length(), &utf16_str[ 0 ], size );
int utf8_size = WideCharToMultiByte( CP_UTF8, 0, utf16_str.c_str(),
utf16_str.length(), nullptr, 0,
nullptr, nullptr );
std::string utf8_str( utf8_size, '\0' );
WideCharToMultiByte( CP_UTF8, 0, utf16_str.c_str(),
utf16_str.length(), &utf8_str[ 0 ], utf8_size,
nullptr, nullptr );
结果是一个std :: string,其大小为3,包含以下字节:
- utf8_str "Ü" std::basic_string<char,std::char_traits<char>,std::allocator<char> >
[size] 0x0000000000000003 unsigned __int64
[capacity] 0x000000000000000f unsigned __int64
[0] 0x55 'U' char
[1] 0xcc 'Ì' char
[2] 0x88 'ˆ' char
当我把它写入utf8文件时。十六进制值保留在那里:0x55 0xCC 0x88
和Notepad ++显示正确的字符Ü
。
然而,当我通过Notepad ++向文件添加另一个Ü
并再次保存时,新写的Ü
显示为0xC3 0x9C
(我实际上预计会在第一时间)。
我不明白,为什么我得到这个字符的3字节表示而不是预期的unicode代码点U + 00DC。
虽然Notepad ++正确显示,但我们的专有系统会将0xC3 0x 9C
呈现为Ü
,并通过渲染0x55 0xCC 0x88
而不会将其识别为两字节utf 8来打破Ü
答案 0 :(得分:6)
Unicode很复杂。获取Ü
至少有两种不同的方式:
LATIN CAPITAL LETTER U WITH DIAERESIS
是Unicode代码点U+00DC
。
LATIN CAPITAL LETTER U
是Unicode代码点U+0055
,COMBINING DIAERESIS
是Unicode代码点U+0308
。
U+00DC
和U+0055 U+0308
都显示为Ü
。
在UTF-8中,Unicode代码点U+00DC
编码为0xC3 0x9C
,U+0055
编码为0x55
,U+0308
编码为0xCC 0x88
}}
您的专有系统似乎有一个错误。
编辑:根据MultiByteToWideChar()
documentation获取您的期望,使用MB_PRECOMPOSED
代替MB_COMPOSITE
。
答案 1 :(得分:2)
虽然编码输出在技术上是正确的,但您可以使用NFC表单解决专有系统中的问题。
在NFC形式中,首先分解所有字符(例如,如果U+00DC
有代码点Ü
,它将被分解为序列U+0055 U+0308
)然后重新组合他们的规范表示(在您的示例中,为U+00DC
)。
在Win32 API中,请参阅NormalizeString()
函数。