Почему в кодировке UTF-8 используется понятие оверлонгов?

#unicode #utf-8

Вопрос:

Это не вопрос типа «что такое сверхдлинность?» или «что мне делать с сверхдлинностями?», поскольку я понимаю, что такое сверхдлинность, и я понимаю, как с ними следует обращаться. Это вопрос, возможно, об истории и, возможно, о каком-то ограничении, которого я не понимаю.

В схеме кодирования UTF-8 вы можете кодировать одну и ту же двоичную последовательность несколькими способами, например:

00101010 , 11000000 10101010 , 11100000 10000000 10101010 , и 11110000 10000000 10000000 10101010

Все технически декодируются в одну и ту же двоичную последовательность 101010 , которая представляет число 42 только с переменным количеством начальных нулей. Конечно, единственная допустимая кодировка в UTF-8-самая короткая. Остальные называются оверлонгами и строго недопустимы в UTF-8.

Но

Похоже, что это и то, и другое:

  1. Пространство расточительно
  2. Усложнение синтаксического анализатора

Если бы вместо этого каждой многобайтовой последовательности было задано начальное целочисленное смещение, то, похоже, было бы:

  1. Нет такой вещи, как слишком длинный
  2. Более простая логика для реализации синтаксических анализаторов
  3. Больше доступных чисел для представления символов

Смещения будут просто следующим возможным целым числом для представления.

длина байта смещение полезные биты
1 0 7
2 2^7 = 128 11
3 2^11 = 2048 16
4 2^16 = 65536 21

Тогда все последовательности, перечисленные выше, будут иметь разные значения:

  • 00101010 = 42
  • 11000000 10101010 = 128 42
  • 11100000 10000000 10101010 = 2048 42
  • 11110000 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). Но я никогда не видел элементов, которые могли бы это подтвердить.