В этой таблице обобщена схема кодирования переменной ширины UTF-8.
Заметив, что используются не все доступные 2-байтовые кодировки, я расширил таблицу, как показано ниже, и увидел, что это справедливо и для 3-байтовых, и для 4-байтовых кодировок (delta
> 0).
| number of bytes | bits available for encodings | number of available encodings | number of codepoints | delta = # avail encodings - # codepoints |
|-----------------|------------------------------|-------------------------------|-----------------------------------------------------|-------------------------------------------|
| 1 | 7 | 2^7 = 128 | 0x80 - 0x00 = 8*16 = 128 | 128 - 128 = 0 |
| 2 | 5+1*6 = 11 | 2^11 = 2,048 | 0x800 - 0x080 = 8*16^2 - 8*16 = 1,920 | 2,048 - 1,920 = 128 |
| 3 | 4+2*6 = 16 | 2^16 = 65,536 | 0x1_0000 - 0x800 = 16^4 - 8*16^2 = 63,488 | 65,336 - 63,488 = 2,048 |
| 4 | 3+3*6 = 21 | 2^21 = 2,097,152 | 0x11_0000 - 0x1_0000 = 0x10_0000 = 16^5 = 1,048,576 | 2,097,152 - 1,048,576 = 1,048,576 |
Есть ли причина, по которой так много кодировок не используются?
0x87F instead of 0x7FF
нет, проверьте битовую комбинацию для 7 (111) и 8 (1000)
@IłyaBursov поправьте меня, если я ошибаюсь, но 0x880 - 0x080 = 0x800 = 8*(16^2) = 8*((2^4)^2) = 8*(2^(4*2)) = 8*(2^8) = (2^3)*(2^8) = 2^11 = 2048
.
0x087F
будет 0b0000_1000 0b0111_1111
, что не будет допустимой 2-байтовой кодировкой
0x07FF
будет 0b0000_0111 0b1111_1111
, что также не будет допустимой 2-байтовой кодировкой.
Или код 0x07FF
будет соответствовать кодировке 0b110_(111)[11] 0b10_[111111]
? (111)
представляет 7
, а [11][111111]
представляет FF
.
Является ли основная цель вопроса: учитывая (например) 2 байта, почему используются только 11 бит, хотя потенциально можно было бы использовать больше (по крайней мере 14), если бы кодировка была другой?
Кодовые точки @joseville являются последовательными, поэтому кодовая точка, но их кодировки — нет, поэтому кодовая точка 0x7FF — последняя кодовая точка, которая может быть закодирована как 2 байта 110_111_11 10_111111
Спасибо за объяснение! Итак, первый 2-байтовый код — U+0080
, который кодируется как 110_000_10 10_00_0000
. Таким образом, кодировки от 110_000_00 10_00_0000
до 110_000_01 10_11_1111
(включительно) не используются.
Примечание. Если вам нужна большая плотность, у нас есть UTF-1, но UTF-8 имеет явное преимущество, и мы (и браузеры) часто используем его также для определения кодировки: чем больше у вас символов в байтах со значениями > 127, тем больше вы конечно, если UTF-8, если вы можете декодировать его с помощью UTF-8 (весьма вероятно, что другая кодировка потерпит неудачу).
Ключевой особенностью UTF-8 является самосинхронизация. Вы можете перейти в середину потока UTF-8 в любой момент и выяснить, где начинается следующий символ. Это связано с тем, что многие значения не могут быть первым байтом символа. Побочным эффектом этого является то, что многие возможные последовательности байтов являются недействительными, поэтому кодирование не настолько плотное, как могло бы быть (требуется больше байтов, чем минимум), но оно делает каждую последовательность однозначной. Это справедливо даже в том случае, если отдельные байты потеряны или повреждены. Декодер всегда может найти начальную точку следующего символа и восстановиться. Это не относится к другим схемам многобайтового кодирования, таким как UTF-16 или Shift-JIS, повторную синхронизацию которых может быть сложно выполнить в случае ошибок.
Особый подход к кодированию длины символа в первом байте аналогичным образом уменьшает двусмысленность в случае пропущенных байтов в потоке или повреждения. Если вы декодируете начальный байт, который указывает, что это 3-байтовый символ, за которым следует другой начальный байт (а не байт продолжения), декодер может узнать, что предыдущий символ поврежден. Этот опережающий индикатор длины также позволяет алгоритмам пропускать заданное количество символов без их декодирования.
Опять же, эти преимущества достигаются за счет размера. Для ASCII стоимость размера равна нулю и довольно скромна для сценариев на основе латиницы. По сравнению с предыдущими национальными системами, она требует около 50% стоимости азиатских кодировок (обычно 3 байта вместо 2) и обычно удваивает размер кириллицы, арабского языка, иврита и греческого языка (обычно 2 байта вместо 1). Но преимущество в том, что есть одна система, которая работает универсально и может смешивать сценарии, а также имеет вышеупомянутые преимущества синхронизации. Таким образом, он стал практически повсеместным, несмотря на его стоимость.
Спасибо! Так, например, для 2-байтовых кодировок не используются следующие 128 кодировок: от 110_000_00 10_00_0000
до 110_000_01 10_11_1111
(включительно). И причина в том, что (некоторые или все?) эти кодировки не допускают «самосинхронизации»? Похоже, что байты продолжения всегда начинаются с 10
. Все, что нужно для самосинхронизации, — это определить, является ли байт байтом-продолжением или нет? Я предполагаю, что, вероятно, происходят более сложные вещи.
@joseville: некоторые комбинации использовались в UTF-8 (первая версия). Из-за UTF-16 и успеха Unicode UCS (или лучше ISO) решила также ограничить максимальное количество кодовых точек. Но раньше вы могли кодировать все 31-битные коды UCS, используя UTF-8 (и более 4 байтов), теперь мы используем только UTF-8. -- Но вы заметите и другие проблемы: один символ (< 128) может быть записан (незаконно как последовательность 2, 3 или 4 байта). Декодеры могут/должны обнаруживать такие случаи и сообщать об ошибках (последствия безопасности).
См. последний абзац en.wikipedia.org/wiki/UTF-8#FSS-UTF для первого пункта en.wikipedia.org/wiki/… для слишком длинных последовательностей.
Неиспользованные кодовые точки откладываются для будущих пакетов.