#unicode #utf-8
Вопрос:
Это не вопрос типа «что такое сверхдлинность?» или «что мне делать с сверхдлинностями?», поскольку я понимаю, что такое сверхдлинность, и я понимаю, как с ними следует обращаться. Это вопрос, возможно, об истории и, возможно, о каком-то ограничении, которого я не понимаю.
В схеме кодирования UTF-8 вы можете кодировать одну и ту же двоичную последовательность несколькими способами, например:
00101010
, 11000000 10101010
, 11100000 10000000 10101010
, и 11110000 10000000 10000000 10101010
Все технически декодируются в одну и ту же двоичную последовательность 101010
, которая представляет число 42
только с переменным количеством начальных нулей. Конечно, единственная допустимая кодировка в UTF-8-самая короткая. Остальные называются оверлонгами и строго недопустимы в UTF-8.
Но
Похоже, что это и то, и другое:
- Пространство расточительно
- Усложнение синтаксического анализатора
Если бы вместо этого каждой многобайтовой последовательности было задано начальное целочисленное смещение, то, похоже, было бы:
- Нет такой вещи, как слишком длинный
- Более простая логика для реализации синтаксических анализаторов
- Больше доступных чисел для представления символов
Смещения будут просто следующим возможным целым числом для представления.
длина байта | смещение | полезные биты |
---|---|---|
1 | 0 | 7 |
2 | 2^7 = 128 | 11 |
3 | 2^11 = 2048 | 16 |
4 | 2^16 = 65536 | 21 |
Тогда все последовательности, перечисленные выше, будут иметь разные значения:
00101010
= 4211000000 10101010
= 128 4211100000 10000000 10101010
= 2048 4211110000 10000000 10000000 10101010
= 65536 42
и максимальное значение UTF-8 будет варьироваться от 2^21 до 2^21 65536.
Есть ли техническая или историческая причина, по которой это не так?
Комментарии:
1. Я бы подумал, что это смутно связано с желанием, чтобы код был самосинхронизирующимся . В UTF-8 начальный байт также указывает длину последовательности, что, по-видимому, не предусмотрено вашим предложением.
2. Структура кодирования не изменилась. Таким
1110xxxx
образом, все равно будет указано еще 2 байта для завершения последовательности и т. Д.3. Как бы то ни было, первоначальное предложение UTF-8 допускало длину последовательностей до шести байт; кодовое пространство Юникода было сокращено в 2003 году, а определение UTF-8 было адаптировано, чтобы разрешить максимум четыре байта.
Ответ №1:
Я думаю, что это просто для простоты (по происхождению). Ваше предложение разумно, и UTF-16 использует его (поэтому добавьте константу к битам, заданным суррогатами).
Но помогает ли это? Как вы можете видеть, вы можете получить очень низкую эффективность: проверьте символ, который можно сократить с помощью вашего предложения: на самом деле это не самые часто используемые символы, поэтому не так много о сжатии текста. И UTF-8 с самосинхронизацией также не предназначен для того, чтобы быть самой короткой последовательностью.
Как вы видите в комментариях, в исходном UTF-8 разрешены все символы UCS, поэтому 31 бит. Только позже (и из-за ограничения UTF-16) UCS и Unicode решили, что максимальное количество символов должно быть U 10FFFF, поэтому ограничили UTF-8 4 байтами.
Примечание: теперь реализация не так проста, потому что следует проверить, нет ли слишком длинных последовательностей (это угроза безопасности), не использовать значения выше максимально допустимой кодовой точки, а также нет значений в суррогатной последовательности. Так что теперь простота на самом деле не соответствует действительности, и с вашим предложением мы пропустили бы первую проверку (и, возможно, самую неприятную).
Примечание: слишком длинные последовательности помогают кодировать
, что является допустимым символом в строке Юникода, но используется в качестве окончания строки на C (и так далее на многих языках и API). Я подозреваю, что это также может быть причиной того, что слишком длинные последовательности делают недопустимую строку UTF-8 (это MUTF-8). Но я никогда не видел элементов, которые могли бы это подтвердить.