3

我们公司正计划让我们的应用程序支持 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 }。如果我将它存储在 a 中std::wstring并计算大小,我得到 1。

现在,让我们以字符 (U+104A2) 作为输入,在 UTF-8 中:F0 90 92 A2。

这一次,它为三个 wchar_t 分配空间并且 std::wstring::size 返回 2即使我认为我只有一个 character

这是有问题的。让我们假设我们以 UTF-8 格式接收数据。我们可以简单地通过不计算等于的字节来计算 Unicode 字符10xxxxxx。我们想将该数据导入到数组中wchar_t以使用它。如果我们只是分配字符数加一,它可能是安全的……直到有人使用 U+FFFF 以上的字符。然后我们的缓冲区将太短,我们的应用程序将崩溃。

那么,对于相同的字符串,以不同的方式编码,计算字符串中字符数的函数会返回不同的值吗?

使用 Unicode 字符串的应用程序是如何设计的以避免这种烦恼?

谢谢您的回复。

4

2 回答 2

7

您必须接受 std::wstring::size没有给出字符数。相反,它为您提供代码单元的数量。如果您有 16 位代码单元,它决定了字符串中有多少个。计算 Unicode 字符的数量需要遍历字符串。一旦你接受它就不会再烦人了。

至于在 UTF-8 中计算字符:不要。相反,您发布的代码很好:调用 MultiByteToWideChar 一次将告诉您需要多少个代码单元,然后您分配正确的数字 - 无论是用于 BMP 字符还是补充平面。如果您绝对想编写自己的计数例程,请使用其中两个:一个用于计算字符,另一个用于计算 16 位代码单元。如果前导字节为 11110xxx,则需要计算两个代码单元。

于 2010-12-07T13:05:43.297 回答
3

我建议您从官方 Unicode 网站阅读以下常见问题解答:http ://www.unicode.org/faq//utf_bom.html

基本上,区分代码单元、代码点和字符是很重要的。

于 2010-12-07T16:46:42.660 回答