Як працює UTF-8 "кодування змінної ширини"?


110

У стандарті unicode є достатня кількість кодових точок, що вам потрібно 4 байти, щоб зберігати їх усі. Ось що робить кодування UTF-32. Однак кодування UTF-8 якимось чином видавлює їх у набагато менші простори, використовуючи щось, що називається "кодування змінної ширини".

Насправді йому вдається представити перші 127 символів US-ASCII лише в одному байті, який виглядає точно як справжній ASCII, тому ви можете інтерпретувати безліч тексту ascii так, ніби це був UTF-8, не роблячи нічого з цим. Акуратний трюк. То як це працює?

Я збираюся запитати і відповісти на моє власне запитання тут, тому що я просто трохи прочитав, щоб зрозуміти це, і я подумав, що це може врятувати когось іншого деякий час. Плюс можливо, хтось може мене виправити, якщо я щось неправильно зрозумів.


8
Для прямого Unicode не потрібно 32 біта, щоб кодувати всі його кодові точки. Колись вони заявляли про багато можливих кодів, але після зняття UTF-8 вони навмисно обмежилися 21 бітом, так що UTF-8 ніколи не перевищуватиме 4 байти на символ. На даний момент Unicode вимагає всього 17 біт, щоб вмістити всі можливі кодові точки. Без цього обмеження UTF-8 міг би перейти до 6 байт на символ.
Warren Young

@Warren: переважно точний, але Unicode - це 21-бітний код (U + 0000 до U + 10FFFF).
Джонатан Леффлер

2
@Warren: 4-байтний UTF-8 міг підтримувати до U + 1FFFFF. Обмеження на U + 10FFFF було зроблено заради UTF-16.
dan04

@ dan04 У нас є легке пояснення того, як це обмежено UT 10FFFF UTF-16? Було б непогано дізнатися про це більше.
A-letubby

@ A-letubby: Оскільки сурогатні коди UTF-16 виділяються таким чином, що є 1024 сурогати свинцю та 1024 сурогати (і їх можна використовувати лише в парі), щоб зробити 2 ^ 20 (близько мільйона) додаткових символів доступні поза BMP. Додано до 2 ^ 16 символів, доступних у BMP, це робить 0x110000 можливих символів.
dan04

Відповіді:


129

Кожен байт починається з декількох бітів, які повідомляють вам, чи є це однобайтова кодова точка, багатобайтова кодова точка або продовження багатобайтової кодової точки. Подобається це:

0xxx xxxx    A single-byte US-ASCII code (from the first 127 characters)

Кожні багатобайтові кодові точки починаються з декількох бітів, які по суті говорять "ей, вам також потрібно прочитати наступний байт (або два, або три), щоб зрозуміти, що я". Вони є:

110x xxxx    One more byte follows
1110 xxxx    Two more bytes follow
1111 0xxx    Three more bytes follow

Нарешті, байти, які слідують за тими початковими кодами, виглядають приблизно так:

10xx xxxx    A continuation of one of the multi-byte characters

Оскільки ви можете сказати, який байт ви дивитеся з перших кількох бітів, то навіть якщо щось десь заблукає, ви не втратите всієї послідовності.


14
Історія має більше, ніж це - тому що кодування має бути найкоротшим можливим кодуванням символу, що в кінцевому підсумку означає, що байти 0xC0 та 0xC1 не можуть відображатися, наприклад, у UTF-8; і насправді ні 0xF5..0xFF не може. Див. Поширені запитання щодо UTF-8 за адресою unicode.org/faq/utf_bom.html або unicode.org/versions/Unicode5.2.0/ch03.pdf
Джонатан Леффлер

2
Чому він не міг сказати лише один знак next char is continuation? Якби ми отримали 3 байтові символи, то це було б так:, 1xxxxxxx 1xxxxxxx 0xxxxxxxзначить, менше місця буде витрачено даремно.

9
@Soaku це робить UTF-8 так званим "самосинхронізуючим" кодом. Це означає, що через помилки частини послідовності відсутні, можна виявити це та відкинути все, що зіпсувалося. Якщо ви прочитаєте байт, який починається з 10xx, і немає попереднього байта "start", ви можете відкинути його як безглуздий. Якщо у вас була така система, як ви описали, і один з перших байтів загублений, ви можете отримати інший, дійсний символ, без вказівки на помилку. Це також полегшить пошук наступного дійсного символу, а також виправить пропущені байти "продовження".
htmlcoderexe

9

RFC3629 - UTF-8, формат перетворення ISO 10646 є остаточним повноваженням тут і має всі пояснення.

Коротше кажучи, кілька бітів у кожному байті кодованої UTF-8 послідовності 1 -4-байт, що представляє один символ, використовуються для вказівки, чи є це трейд-байт, провідний байт, і якщо так, то скільки байтів слід. Решта бітів містять корисне навантаження.


1
Уммм, нерозумно мені, я думав, що стандарт Unicode став остаточним органом UTF-8
Джон Махін

6
Стандарт Unicode визначає сам Unicode. Він не визначає різні методи, сьогоднішні та майбутні, які можна використовувати для кодування текстів унікоду для різних цілей (наприклад, зберігання та транспортування). UTF-8 є одним із таких методів, і вище посилання на документ, який його визначає.
ажеглов

1
RFC3629, сторінка 3, розділ 3. говорить: "UTF-8 визначено стандартом Unicode".
Джон Махін

Переслідування посилань на unicode.org перевело мене до розділу 3.9 стандарту Unicode та конкретно до визначення D92 (а також дотично D86). Я не маю уявлення, якою мірою це посилання буде корисним при випуску нових версій, але я думаю, що вони хочуть підтримувати ідентифікатори розділу та визначення стабільними у різних версіях.
трійка

4

UTF-8 була ще однією системою для зберігання вашого рядка кодових точок Unicode, тих чарівних чисел U +, в пам'яті за допомогою 8-бітових байтів. У UTF-8 кожна кодова точка від 0-127 зберігається в одному байті. Лише кодові точки 128 і вище зберігаються, використовуючи 2, 3, фактично, до 6 байт.

Витяг з абсолютного мінімуму кожен розробник програмного забезпечення повинен абсолютно, позитивно знати про набори Unicode та символів (без виправдань!)


Це гарна стаття, але, схоже, Джоел помиляється щодо максимальної тривалості послідовності; на сторінці Вікіпедії відображається лише 1,4 байти на символ.
розмотайте

4
Як я вже говорив вище, коли UTF-8 був створений вперше, Unicode пред'являє претензії до 32-бітових кодів для кодових очок, а не тому, що їм це справді потрібно, а тому, що 32-біт - це зручне значення, і вони вже задули минуле попередня межа 16-бітових символів. Після того, як UTF-8 виявився популярним, вони вирішили назавжди обмежити максимальну кількість точок коду до 2 ^ 21, що є найбільшим значенням, яке ви можете кодувати за допомогою 4-х байт схеми UTF-8. У Unicode все ще менше ніж 2 ^ 17 символів, тому ми можемо більше ніж учетверо збільшити кількість символів у Unicode за допомогою цієї нової схеми.
Воррен Янг

Гаразд, але не пояснення, яке просить ОП.
Нішант

2
Це не дає відповіді на запитання.
Корай Тугай
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.