Есть ли причина предпочитать UTF-16 UTF-8? - PullRequest
27 голосов
/ 29 мая 2010

Изучая атрибуты UTF-16 и UTF-8, я не могу найти никаких причин, чтобы предпочесть UTF-16.

Однако, проверяя Java и C #, похоже, что строки и символы там по умолчанию - UTF-16. Я думал, что это может быть по историческим причинам, или, возможно, по причинам производительности, но не смог найти никакой информации.

Кто-нибудь знает, почему эти языки выбрали UTF-16? И есть ли для меня веская причина сделать это?

РЕДАКТИРОВАТЬ: Между тем я также нашел этот ответ , который представляется актуальным и имеет некоторые интересные ссылки.

Ответы [ 6 ]

32 голосов
/ 29 мая 2010

В восточноазиатских языках обычно требуется меньше памяти в UTF-16 (для 99% символов восточноазиатского языка достаточно 2 байта), чем в UTF-8 (обычно требуется 3 байта).

Конечно, для западных ланге UTF-8 обычно меньше (1 байт вместо 2). Для смешанных файлов, таких как HTML (где много разметки), это очень много.

Обработка UTF-16 для приложений пользовательского режима немного проще, чем обработка UTF-8, потому что суррогатные пары ведут себя почти так же, как и при объединении символов. Таким образом, UTF-16 обычно может обрабатываться как кодировка фиксированного размера.

10 голосов
/ 29 мая 2010

@ Дуб: это слишком долго для комментария ...

Я не знаю о C # (и был бы очень удивлен: это означало бы, что они просто скопировали Java слишком много), но для Java все просто: Java была задумана еще до выхода Unicode 3.1.

Следовательно, было меньше 65537 кодовых точек, следовательно, каждая кодовая точка Unicode все еще соответствовала 16-битной, и таким образом родился Java char .

Конечно, это привело к сумасшедшим проблемам, которые все еще затрагивают программистов Java (таких как я) сегодня, когда у вас есть метод charAt , который в некоторых случаях не возвращает ни символа Unicode, ни кода Unicode, ни метод (добавлен в Java 5) codePointAt , который принимает аргумент, который не является числом кодовых точек, которое вы хотите пропустить! (вам нужно указать codePointAt номер Java char , который вы хотите пропустить, что делает его одним из наименее понятных методов в классе String).

Итак, да, это определенно дико и сбивает с толку большинство Java-программистов (большинство даже не знают об этих проблемах), и да, это по исторической причине. По крайней мере, это было оправданием, когда люди злились после этой проблемы: , но это потому, что Unicode 3.1 еще не вышел .

:)

7 голосов
/ 29 мая 2010

Я предполагаю, что C #, использующий UTF-16, происходит от семейства операционных систем Windows NT, использующих UTF-16 внутри.

Я полагаю, что есть две основные причины, по которым Windows NT использует UTF-16 внутри:

  • Для использования памяти: UTF-32 тратит впустую много места для кодирования.
  • Для производительности: UTF-8 гораздо сложнее декодировать, чем UTF-16. В UTF-16 символы либо символ базовой многоязычной плоскости (2 байта) или суррогат Пара (4 байта). Символы UTF-8 может быть где угодно между 1 и 4 байт.

Вопреки ответам других людей - вы не можете рассматривать UTF-16 как UCS-2 . Если вы хотите правильно выполнять итерацию по фактическим символам в строке, вы должны использовать дружественные к юникоду функции итерации. Например, в C # вам нужно использовать StringInfo.GetTextElementEnumerator().

Для получения дополнительной информации, эта страница в вики стоит прочитать: http://en.wikipedia.org/wiki/Comparison_of_Unicode_encodings

3 голосов
/ 29 мая 2010

UTF-16 может быть более эффективным для представления символов на некоторых языках, таких как китайский, японский и корейский, где большинство символов могут быть представлены в одном 16-битном слове. Некоторые редко используемые символы могут требовать двух 16-битных слов. UTF-8, как правило, гораздо более эффективен для представления символов из западноевропейских наборов символов - UTF-8 и ASCII эквивалентны во всем диапазоне ASCII (0-127) - но менее эффективен для азиатских языков, требующих три или четыре байта для представления символов может быть представлен двумя байтами в UTF-16.

UTF-16 имеет преимущество в качестве формата в памяти для Java / C #, заключающееся в том, что каждый символ в базовой многоязычной плоскости может быть представлен в 16 битах (см. Ответ Джо) и некоторые недостатки UTF-16 (например, сбивающий с толку код, использующий терминаторы \ 0), менее актуален.

3 голосов
/ 29 мая 2010

Зависит от ожидаемых наборов символов. Если вы ожидаете интенсивного использования кодовых точек Unicode за пределами 7-битного диапазона ASCII, то вы можете обнаружить, что UTF-16 будет более компактным, чем UTF-8, поскольку некоторые последовательности UTF-8 имеют длину более двух байтов.

Кроме того, по соображениям эффективности Java и C # не учитывают суррогатные пары при индексации строк. Это полностью сломалось бы при использовании кодовых точек, представленных последовательностями UTF-8, которые занимают нечетное число байтов.

2 голосов
/ 29 мая 2010

Для многих (большинства?) Приложений вы будете иметь дело только с символами в Базовой многоязычной плоскости , поэтому можете рассматривать UTF-16 как кодировку фиксированной длины.

Таким образом, вы избегаете всей сложности кодировок переменной длины, таких как UTF-8.

...