wchar_t является 2-байтовым в визуальной студии и хранит UTF-16.Как приложения с поддержкой Unicode работают с символами выше U + FFFF? - PullRequest
3 голосов
/ 07 декабря 2010

Мы в нашей компании планируем сделать наше приложение поддерживающим Юникод, и мы анализируем, какие проблемы нам предстоит встретить.

В частности, наше приложение будет, например, сильно полагаться на длины строк, и мы хотели бы использовать wchar_t в качестве базового класса символов.

Проблема возникает при работе с символами, которые должны храниться в 2 единицах по 16 битов в UTF-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. Мы хотели бы импортировать эти данные в массив wchar_t для работы с ним. Если мы просто выделим количество символов плюс один, это может быть безопасно ... пока кто-нибудь не использует символ выше U + FFFF. И тогда наш буфер будет слишком коротким, и наше приложение вылетит.

Итак, с одной и той же строкой, кодированной по-разному, функции, считающие символы в строке, будут возвращать разные значения?

Как разрабатываются приложения, работающие со строками Unicode, чтобы избежать такого рода раздражений?

Спасибо за ваши ответы.

Ответы [ 2 ]

6 голосов
/ 07 декабря 2010

Вы должны принять, что std :: wstring :: size не дает количество символов. Вместо этого он дает вам количество единиц кода. Если у вас есть 16-битные единицы кода, он определяет, сколько из них у вас в строке. Вычисление количества символов Unicode потребует циклического перемещения по строке. Это больше не будет раздражать, как только ты примешь это.

Что касается подсчета символов в UTF-8: не делайте. Вместо этого, код, который вы разместили, в порядке: вызов MultiByteToWideChar один раз скажет вам, сколько единиц кода вам нужно, а затем вы выделите правильное число - будь то символы BMP или дополнительные плоскости. Если вы абсолютно хотите написать свои собственные процедуры подсчета, имейте две из них: одну, которая считает символы, и одну, которая считает 16-битные единицы кода. Если старший байт 11110xxx, вам необходимо сосчитать две кодовые единицы.

3 голосов
/ 07 декабря 2010

Я предлагаю вам прочитать следующие часто задаваемые вопросы с официального сайта Unicode: http://www.unicode.org/faq//utf_bom.html

В принципе, важно различать единицы кода, кодовые точки и символы.

...