Нет символа Юникод, который может быть сохранен в одной кодировке, но не в другой. Это просто потому, что допустимые символы 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).