Отличаются ли UTF-8, UTF-16 и UTF-32 количеством символов, которые они могут хранить? - PullRequest
46 голосов
/ 25 сентября 2008

Хорошо. Я знаю, что это похоже на типичный «Почему он просто не прогуглил его или не зашел на www.unicode.org и не нашел его?» вопрос, но для такого простого вопроса ответ все еще ускользает от меня после проверки обоих источников.

Я почти уверен, что все три из этих систем кодирования поддерживают все символы Unicode, но мне нужно подтвердить это, прежде чем я сделаю это заявление в презентации.

Дополнительный вопрос: отличаются ли эти кодировки количеством символов, которые они могут расширять для поддержки?

Ответы [ 6 ]

55 голосов
/ 11 ноября 2008

Нет символа Юникод, который может быть сохранен в одной кодировке, но не в другой. Это просто потому, что допустимые символы Unicode были ограничены тем, что может быть сохранено в UTF-16 (который имеет наименьшую емкость из трех кодировок). Другими словами, UTF-8 и UTF-32 могут использоваться для представления более широкого диапазона символов, чем UTF-16, но они не . Читайте дальше для более подробной информации.

UTF-8

UTF-8 - код переменной длины. Некоторым символам требуется 1 байт, некоторым - 2, некоторым 3 и некоторым 4. Байты для каждого символа просто записываются один за другим как непрерывный поток байтов.

Хотя некоторые символы UTF-8 могут иметь длину 4 байта, UTF-8 не может кодировать 2 ^ 32 символа . Это даже не близко. Я постараюсь объяснить причины этого.

Программное обеспечение, которое читает поток UTF-8, просто получает последовательность байтов - как она должна решить, являются ли следующие 4 байта одиночным 4-байтовым символом, или двумя 2-байтовыми символами, или четырьмя 1-байтовыми символы (или какая-то другая комбинация)? В основном это делается путем принятия решения о том, что определенные 1-байтовые последовательности не являются допустимыми символами, а некоторые 2-байтовые последовательности не являются допустимыми символами и т. Д. Когда появляются эти недопустимые последовательности, предполагается, что они образуют часть более длинной последовательности.

Вы видели довольно другой пример этого, я уверен: это называется побег. Во многих языках программирования принято, что символ \ в исходном коде строки не переводится ни в один допустимый символ в «скомпилированной» форме строки. Когда в источнике находится символ \, предполагается, что он является частью более длинной последовательности, например \n или \xFF. Обратите внимание, что \x является недопустимой 2-символьной последовательностью, а \xF является недопустимой 3-символьной последовательностью, но \xFF является допустимой 4-символьной последовательностью.

По сути, существует компромисс между количеством символов и более короткими символами. Если вы хотите 2 ^ 32 символа, они должны быть в среднем 4 байта длиной. Если вы хотите, чтобы все ваши символы были размером 2 байта или меньше, то вы не можете иметь более 2 ^ 16 символов. UTF-8 дает разумный компромисс: всем ASCII символам (ASCII от 0 до 127) даны однобайтовые представления, что отлично подходит для совместимости, но допускается гораздо больше символов.

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

Например, символ «А» представлен с использованием байта 65, и нет двух / трех / четырехбайтовых символов, чей первый байт равен 65. В противном случае декодер не сможет отличить эти символы от «А», за которым следует что-то еще.

Но UTF-8 ограничен еще больше. Это гарантирует, что кодировка более короткого символа никогда не появится в любом месте в кодировке более длинного символа. Например, ни один из байтов в 4-байтовом символе не может быть 65.

Так как UTF-8 имеет 128 различных 1-байтовых символов (значения байтов 0-127), все 2, 3 и 4-байтовые символы должны состоять исключительно из байтов в диапазоне 128-256. Это большое ограничение. Однако он позволяет байтово-ориентированным строковым функциям работать практически без изменений. Например, функция C strstr() всегда работает должным образом, если ее входные данные являются допустимыми строками UTF-8.

UTF-16

UTF-16 также является кодом переменной длины; его символы занимают 2 или 4 байта. 2-байтовые значения в диапазоне 0xD800-0xDFFF зарезервированы для построения 4-байтовых символов, а все 4-байтовые символы состоят из двух байтов в диапазоне 0xD800-0xDBFF, за которыми следуют 2 байта в диапазоне 0xDC00-0xDFFF. По этой причине Unicode не назначает никаких символов в диапазоне U + D800-U + DFFF.

UTF-32

UTF-32 - это код фиксированной длины, каждый символ длиной 4 байта. Хотя это позволяет кодировать 2 ^ 32 различных символов, в этой схеме разрешены только значения от 0 до 0x10FFFF.

Сравнение мощностей:

  • UTF-8: 2 097 152 (фактически 2 166 912, но из-за особенностей конструкции некоторые из них соответствуют одному и тому же)
  • UTF-16: 1 112 064
  • UTF-32: 4 294 967 296 (но ограничено первыми 1 114 114)

Поэтому самым ограниченным является UTF-16! Формальное определение Unicode ограничило символы Unicode теми, которые могут быть закодированы с помощью UTF-16 (то есть диапазон от U + 0000 до U + 10FFFF, исключая U + D800 до U + DFFF). UTF-8 и UTF-32 поддерживают все эти символы.

Система UTF-8 фактически «искусственно» ограничена 4 байтами. Его можно увеличить до 8 байт, не нарушая ограничений, которые я обрисовал ранее, и это даст емкость 2 ^ 42. Оригинальная спецификация UTF-8 фактически допускает до 6 байтов, что дает емкость 2 ^ 31. Но RFC 3629 ограничил его 4 байтами, поскольку именно столько нужно, чтобы покрыть все, что делает UTF-16.

Существуют и другие (в основном исторические) схемы кодирования Unicode, в частности UCS-2 (которая способна только кодировать U + 0000 в U + FFFF).

39 голосов
/ 25 сентября 2008

Нет, это просто разные методы кодирования. Все они поддерживают кодирование одного и того же набора символов.

UTF-8 использует от одного до четырех байтов на символ в зависимости от того, какой символ вы кодируете. Символы в диапазоне ASCII занимают только один байт, а очень необычные символы - четыре.

UTF-32 использует четыре байта на символ независимо от того, какой это символ, поэтому он всегда будет использовать больше места, чем UTF-8, для кодирования одной и той же строки. Единственным преимуществом является то, что вы можете вычислить количество символов в строке UTF-32, считая только байты.

UTF-16 использует два байта для большинства символов, четыре байта для необычных.

http://en.wikipedia.org/wiki/Comparison_of_Unicode_encodings

7 голосов
/ 25 сентября 2008

UTF-8, UTF-16 и UTF-32 поддерживают полный набор кодовых точек Unicode. Нет символов, которые поддерживаются одним, но не другим.

Что касается бонусного вопроса "Различаются ли эти кодировки количеством символов, которые они могут быть расширены для поддержки?" И да и нет. Способ кодирования UTF-8 и UTF-16 ограничивает общее число кодовых точек, которые они могут поддерживать, до менее чем 2 ^ 32. Однако Консорциум Unicode не будет добавлять кодовые точки к UTF-32, которые не могут быть представлены в UTF-8 или UTF-16. Это нарушит дух стандартов кодирования и сделает невозможным однозначное сопоставление UTF-32 с UTF-8 (или UTF-16).

5 голосов
/ 25 сентября 2008

Я лично всегда проверяю пост Джоэла о юникоде, кодировках и наборах символов, если сомневаетесь.

4 голосов
/ 25 сентября 2008

Все кодировки UTF-8/16/32 могут отображать все символы Unicode. См. Сравнение кодировок Unicode в Википедии .

Эта статья IBM Кодирование ваших XML-документов в UTF-8 очень полезно и указывает, что если у вас есть выбор, лучше выбрать UTF-8. Главным образом причины - широкая поддержка инструментов, и UTF-8 может обычно проходить через системы, которые не знают о юникоде.

Из раздела Что говорят спецификации в статье IBM :

И W3C, и IETF имеют недавно стал более непреклонным выбирая UTF-8 первым, последним и иногда только. Персонаж W3C Модель для World Wide Web 1.0: Основы гласят: «Когда уникальный требуется кодировка символов, кодировка символов ДОЛЖНА быть UTF-8, UTF-16 или UTF-32. US-ASCII является совместим с UTF-8 ( US-ASCII строка также является UTF-8 строка, см. [RFC 3629]), а UTF-8 поэтому уместно, если совместимость с США-ASCII желательно ". В практика, совместимость с US-ASCII это так полезно, это почти требование. W3C мудро объясняет, «В других ситуациях, например, для API, UTF-16 или UTF-32 может быть больше подходящее. Возможные причины Выбор одного из них включает эффективность внутренней обработки и совместимость с другими процессы ".

2 голосов
/ 25 сентября 2008

Как уже говорили, UTF-8, UTF-16 и UTF-32 могут кодировать все кодовые точки Unicode. Однако вариант UCS-2 (иногда ошибочно называемый UCS-16) не может , и это тот, который вы найдете, например. в Windows XP / Vista .

См. Википедия для получения дополнительной информации.

Редактировать: Я ошибаюсь в Windows, NT была единственной, кто поддерживал UCS-2. Тем не менее, многие приложения Windows будут использовать одно слово для каждой кодовой точки, как в UCS-2, поэтому вы, вероятно, найдете ошибки. См. другая статья в Википедии . (Спасибо ДжейсонТру)

...