我们正在计划让我们的应用程序识别Unicode,我们正在分析我们将遇到的问题。
特别是,我们的应用程序将严重依赖字符串的长度,我们希望使用wchar_t
作为基本字符类。
当处理必须以UTF-16中的2个16位为单位存储的字符时出现问题,即U + 10000以上的字符。
简单示例:
我有UTF-8字符串“蟂”(Unicode字符U + 87C2,UTF-8:E8 9F 82)
所以,我设置了以下代码:
const unsigned char my_utf8_string[] = { 0xe8, 0x9f, 0x82, 0x00 };
// compute size of wchar_t buffer.
int nb_chars = ::MultiByteToWideChar(CP_UTF8, // input is UTF8
0, // no flags
reinterpret_cast<char *>(my_utf8_string), // input string (no worries about signedness)
-1, // input is zero-terminated
NULL, // no output this time
0); // need the necessary buffer size
// allocate
wchar_t *my_utf16_string = new wchar_t[nb_chars];
// convert
nb_chars = ::MultiByteToWideChar(CP_UTF8,
0,
reinterpret_cast<char *>(my_utf8_string),
-1,
my_widechar_string, // output buffer
nb_chars); // allocated size
好的,这可行,它分配两次16位,而wchar_t
的缓冲区包含{0x87c2,0x0000}。如果我将它存储在std::wstring
内并计算大小,我会得到1。
现在,让我们将字符(U + 104A2)作为输入,采用UTF-8:F0 90 92 A2。
这次,它为三个wchar_t和std :: wstring :: size返回2 分配空间,即使我认为我只有一个字符。
这是有问题的。我们假设我们以UTF-8接收数据。我们可以简单地通过不计算等于10xxxxxx
的字节来计算Unicode字符。我们希望在wchar_t
数组中导入该数据以使用它。如果我们只是分配字符数加1,那么可能是安全的...直到有人使用U + FFFF以上的字符。然后我们的缓冲区将太短,我们的应用程序将崩溃。
因此,使用以不同方式编码的相同字符串,计算字符串中字符数的函数将返回不同的值吗?
如何设计适用于Unicode字符串的应用程序以避免这种烦恼?
感谢您的回复。
答案 0 :(得分:6)
你必须接受std :: wstring :: size 不给出字符数。相反,它为您提供了代码单元的数量。如果您有16位代码单元,它将确定您在字符串中有多少代码单元。计算Unicode字符的数量需要在字符串上循环。一旦你接受它就不再烦人了。
至于计算UTF-8中的字符:不要。相反,您发布的代码很好:调用MultiByteToWideChar一次会告诉您需要多少代码单元,然后分配正确的数字 - 无论是BMP字符还是辅助平面。如果您绝对想要编写自己的计数例程,请使用其中两个:一个计算字符数,另一个计算16位代码单位数。如果前导字节是11110xxx,则需要计算两个代码单元。
答案 1 :(得分:3)
我建议您阅读官方Unicode网站上的以下常见问题解答:http://www.unicode.org/faq//utf_bom.html
基本上,区分代码单元,代码点和字符非常重要。