Каково максимальное количество байтов для символа в кодировке UTF-8?

79

Каково максимальное количество байтов для одного символа в кодировке UTF-8?

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

Может ли кто-нибудь подтвердить максимальное количество байтов для одного символа в кодировке UTF-8, пожалуйста

Эдд
источник
1
Вы сначала посмотрели общие ресурсы, такие как статья Википедии о UTF-8 ... верно?
5
Я прочитал несколько статей, которые давали смешанные ответы ... У меня действительно создалось впечатление, что ответ был 3, поэтому я очень рад, что спросил
Эдд
2
Я оставлю здесь ссылку на YouTube, в которой представлены персонажи, символы и чудо Unicode Тома Скотта: goo.gl/sUr1Hf . Вы можете услышать и увидеть, как все развивается от кодировки символов ASCII до utf-8.
Рой Ли
См. Также Вычисление длины в UTF-8 строки Java без фактического кодирования для примера кода вычисления длины
Вадим,

Ответы:

86

Максимальное количество байтов на символ составляет 4 в соответствии с RFC3629, который ограничивает таблицу символов следующим образом U+10FFFF:

В UTF-8 символы из диапазона U + 0000..U + 10FFFF (доступный диапазон UTF-16) кодируются с использованием последовательностей от 1 до 4 октетов.

(Исходная спецификация допускала до шести байтовых кодов символов для прошлых кодовых точек U+10FFFF.)

Для символов с кодом меньше 128 потребуется только 1 байт, а для следующих 1920 кодов символов потребуется только 2 байта. Если вы не работаете с эзотерическим языком, умножение количества символов на 4 будет значительным переоценкой.

Тамаш
источник
7
Что для вас «эзотерический язык»? Любой язык, который существует в реальном мире, или текст, который переключается между разными языками мира? Должен ли разработчик функции UTF-8-to-String выбрать 2, 3 или 4 в качестве мультипликатора, если он выполняет избыточное выделение и уменьшает результат после фактического преобразования?
Дэниел Маршалл
1
@rinntech под «эзотерическим языком» он имеет в виду язык, который имеет много ценных символов Unicode (что-то из конца этого списка: unicode-table.com/en/sections ). Если вам необходимо выделить больше, выберите 4. Вы можете выполнить двойной проход, один, чтобы увидеть, сколько байтов вам нужно и выделить, а другой - для кодирования; это может быть лучше, чем выделять в ~ 4 раза больше необходимой оперативной памяти.
matiu
9
Всегда старайтесь справиться с худшим случаем: hacker9.com/single-message-can-crash-whatsapp.html
Evgen
20
Символы CJKV в основном занимают 3 байта (с некоторыми редкими / архаичными символами, занимающими 4 байта), и называть их эзотерическими немного натянуто (только Китай составляет почти 20% населения мира ...).
Tgr
3
Почему было ограничено 4, когда раньше было 6? Что мешает нам продолжать стандарт и иметь ведущий байт 11111111и 2^(6*7)немного места для символов?
Аарон Франке
32

Без дальнейшего контекста я бы сказал, что максимальное количество байтов для символа в UTF-8 составляет

ответ: 6 байт

Автор принятого ответа правильно указал на это как на «исходную спецификацию». Это действовало до RFC-2279 1 . Как отметил Дж. Коко в комментариях ниже, это изменилось в 2003 году с появлением RFC-3629 2 , который ограничивает UTF-8 кодированием для 21 бита, что может быть обработано схемой кодирования с использованием четырех байтов.

ответ, если покрывает весь юникод: 4 байта

Но в Java <= v7 они говорят о 3-байтовом максимуме для представления Unicode с UTF-8? Это потому, что исходная спецификация Unicode определяла только базовую многоязычную плоскость ( BMP ), то есть это более старая версия unicode или подмножество современного unicode. Так

ответ, если представляет только исходный юникод, BMP: 3 байта

Но ОП говорит о том, чтобы пойти другим путем. Не из символов в байты UTF-8, а из байтов UTF-8 в «Строку» байтового представления. Возможно, автор принятого ответа получил это из контекста вопроса, но это не обязательно очевидно, поэтому может сбить с толку случайного читателя этого вопроса.

Переходя от UTF-8 к собственной кодировке, мы должны посмотреть, как реализована «строка». Некоторые языки, такие как Python> = 3, будут представлять каждый символ целыми кодовыми точками, что позволяет использовать 4 байта на символ = 32 бита, чтобы покрыть 21, который нам нужен для Unicode, с некоторыми потерями. Почему не совсем 21 бит? Потому что все происходит быстрее, когда они выровнены по байтам. Некоторые языки, такие как Python <= 2 и Java, представляют символы с использованием кодировки UTF-16, что означает, что они должны использовать суррогатные пары для представления расширенного юникода (не BMP). В любом случае это все еще максимум 4 байта.

ответьте, если идете UTF-8 -> собственная кодировка: 4 байта

Итак, окончательный вывод, 4 - наиболее распространенный правильный ответ, так что мы все правильно поняли. Но пробег может отличаться.

Джошуа Ричардсон
источник
5
"это все еще текущая и правильная спецификация, согласно Википедии" - больше нет. Вскоре после того, как вы написали это (редактирование от 2 апреля), статья Википедии о UTF-8 была изменена, чтобы уточнить, что 6-октетная версия не является частью текущей (2003 г.) спецификации UTF-8.
Дж. Кокоэ
«Но в Java <= v7 они говорят о 3-байтовом максимуме для представления юникода с UTF-8? Это потому, что исходная спецификация юникода определяла только базовую многоязычную плоскость» - это, вероятно, первоначальная причина, но это не вся история. Java использует "модифицированный UTF-8", и одна из модификаций заключается в том, что он "использует свой собственный трехбайтовый формат" вместо "четырехбайтового формата стандартного UTF-8" (их слова).
J. Cocoe
1
Нет кодовых точек, выделенных выше лимита 10FFFF (чуть более миллиона), и многие реализации UTF8 никогда не реализовывали последовательности длиннее 4 байтов (а некоторые только 3, например MySQL), поэтому я считаю безопасным жесткое ограничение до 4 байтов на codepoint даже при рассмотрении совместимости со старыми реализациями. Вам просто нужно убедиться, что вы отбрасываете все недопустимые по пути. Обратите внимание, что рекомендация matiu о выделении после вычисления точной длины байта является хорошей там, где это возможно.
thomasrutter
2
«... [U] nicode может представлять до x10FFFF кодовых точек. Таким образом, включение 0 означает, что мы можем делать это с помощью следующих байтов: F FF FF, то есть два с половиной байта или 20 бит». Я считаю, что это немного неправильно. Число кодовых точек от 0x0 до 0x10FFFF будет 0x110000, что может быть представлено в 1F FF FFили 21 бит. Число 0x110000 соответствует 17 плоскостям с кодовыми точками 0x10000 каждая.
neuralmer
2
PSA: Википедия не является настоящим источником. Посмотрите актуальные ссылки в статье.
Nyerguds
0

Максимальное количество байтов для поддержки US-ASCII, стандартной кодировки английского алфавита, равно 1. Но ограничение текста английским языком становится все менее желательным или практичным с течением времени.

Unicode был разработан для представления глифов всех человеческих языков, а также многих видов символов с различными характеристиками воспроизведения. UTF-8 - эффективная кодировка для Unicode, хотя по-прежнему смещена в сторону английского языка. UTF-8 является самосинхронизирующимся: границы символов легко идентифицируются путем сканирования четко определенных битовых шаблонов в любом направлении.

Хотя максимальное количество байтов на символ UTF-8 составляет 3 для поддержки только 2-байтового адресного пространства плоскости 0, базовой многоязычной плоскости (BMP), которая может быть принята как минимальная поддержка в некоторых приложениях, это 4 для поддержки все 17 текущих плоскостей Unicode (по состоянию на 2019 год). Следует отметить, что многие популярные символы «эмодзи», вероятно, будут расположены в плоскости 16, для которой требуется 4 байта.

Однако это только для основных символов символов. Существуют также различные модификаторы, такие как добавление акцентов к предыдущему символу, и также можно связать вместе произвольное количество кодовых точек для создания одной сложной «графемы». Поэтому в реальном программировании использование или допущение фиксированного максимального количества байтов на символ, вероятно, в конечном итоге приведет к проблемам для вашего приложения.

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

Дэвид Спектор
источник
Примечание: абзац об отказе от использования массива символов фиксированной ширины - это мое личное мнение. Я готов отредактировать этот ответ в ответ на комментарии.
Дэвид Спектор