UTF против типов символов - PullRequest
       39

UTF против типов символов

0 голосов
/ 08 ноября 2019

UTF-8 и UTF-16 имеют переменную длину - может использоваться более 2 байтов. UTF-32 использует 4 байта. Unicode и UTF являются общими понятиями, но мне интересно, как это связано с типами символов C / C ++. Windows (WinApi) использует 2 байта wchar_t. Как обработать символ UTF-8, который длиннее двух байтов? Даже в Linux, где длина wchar_t составляет 4 байта, я могу получить символы UTF-8, для которых требуется 6 байтов. Пожалуйста, объясните, как это работает.

Ответы [ 2 ]

4 голосов
/ 08 ноября 2019

Старайтесь не перепутать кодовую точку Unicode и ее представление в конкретной кодировке. Все Кодовые точки Unicode находятся в диапазоне 0x0 - 0x10FFFF, что делает их непосредственно сохраняемыми как 32-разрядные числа (это то, что делает UTF-32).

UTF-8 может достигать 6 байт на кодовую точку [править: в действительности это 4 в окончательной версии, поэтому проблема с пространством спорна, но остальная часть параграфа остается в силе], потому что для управления ее переменной длиной требуются некоторые издержки - эточто позволяет кодировать множество других кодовых точек только в 1 или 2 байта. Но когда вы получаете 6-байтовый символ UTF-8 и хотите сохранить его в 32-битном wchar_t Linux, вы не сохраняете его как есть: вы преобразовать его в UTF-32, отбрасывая накладные расходы. Та же история с 16-битным Windows wchar_t, за исключением того, что вы можете получить 2 16-битные половины в кодировке UTF-16.

Примечание: многие программы Windows на самом деле используют UCS-2, которыйпо сути UTF-16 без переменной длины. Они не смогут обрабатывать символы, для которых потребовалось бы два UTF-16 wchar_t.

2 голосов
/ 08 ноября 2019

Прежде всего, максимальный Unicode символ (UTF-8, UTF-16 и UTF-32 представляют собой кодировки Unicode в байтах) равен U + 10FFFF, что удобно подходитв 4-байтовом wchar_t.

Что касается 2 байтов wchar_t, Unicode решил эту проблему в UTF-16, добавив фиктивные «суррогатные» символы в диапазоне от U + D800 до U + DFFF.

Цитирование примера со страницы UTF-16 в Википедии :

Для кодирования U + 10437 (?) в UTF-16:
Вычесть0x10000 от кодовой точки, оставляя 0x0437.
Для старшего суррогата сдвиньте вправо на 10 (разделите на 0x400), затем добавьте 0xD800, в результате чего 0x0001 + 0xD800 = 0xD801.
Для низкого суррогата возьмите младшее10 битов (остаток от деления на 0x400), затем добавьте 0xDC00, в результате чего 0x0037 + 0xDC00 = 0xDC37.

Для полноты, вот этот символ, закодированный в различных кодировках:

  • UTF-8: 0xF0 0x90 0x90 0xB7
  • UTF-16: 0xD801 0xDC37
  • UTF-32: 0x00010437
...