Чому UTF-8 витрачає кілька біт на його кодування


17

Відповідно до статті Wikipedia , UTF-8 має такий формат:

Перший код Останній код Байт 1 Байт 2 Байт 3 Байт 4
точкова точка Використовується
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 07FF 2 110xxxxx 10xxxxxx
U + 0800 U + FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
U + 10000 U + 1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
x означає, що цей біт використовується для вибору кодової точки.

Це витрачає два біти на кожен байт продовження і один біт у перший байт. Чому UTF-8 не кодується так:

Перший код Останній код Байт 1 Байт 2 Байт 3
точкова точка Використовується
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 3FFF 2 10xxxxxx xxxxxxxx
U + 0800 U + 1FFFFF 3 110xxxxx xxxxxxxx xxxxxxxx

Це дозволить зберегти один байт, коли кодова точка знаходиться поза базовою багатомовною площиною або якщо точка коду знаходиться в діапазоні [U + 800, U + 3FFF].

Чому UTF-8 не кодується більш ефективно?


3
cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt Пропоноване кодування схоже на оригінальну пропозицію FSS / UTF. Кен Томпсон та Роб Пайк хотіли власності, що синхронізується.
ninjalj

4
Крім того, ваше кодування, здається, не гарантує, що значення коду ASCII не відображаються в жодній частині представлення для символів, що не належать до ASCII. FSS / UTF і UTF-8 призначені для роботи зі застарілими програмами (наприклад, з тими, що використовують ASCII NUL та слэш (роздільник шляху) як роздільники).
ніндзя

Відповіді:


26

Це робиться для того, щоб ви могли виявити, коли ви знаходитесь в середині багатобайтової послідовності. Переглядаючи дані UTF-8, ви знаєте, що якщо ви бачите 10xxxxxx, що ви перебуваєте в середині багатобайтового символу, і вам слід створити резервну копію в потоці, поки ви не побачите 0xxxxxxабо 11xxxxxx. Використовуючи вашу схему, байти 2 або 3 можуть легко закінчитися малюнками типу " 0xxxxxxxабо"11xxxxxx

Також майте на увазі, що кількість збережених залежить повністю від того, який тип рядкових даних ви кодуєте. У більшості текстів, навіть азіатських, ви рідко бачите чотири байтних символів із звичайним текстом. Також наївні оцінки людей щодо того, як буде виглядати текст, часто помиляються. У мене локалізований текст для UTF-8, який включає рядки японської, китайської та корейської мов, але саме російська мова займає найбільше місця. (Оскільки в наших азіатських рядках часто римські символи перемежовуються для власних імен, пунктуацій та подібних даних, а середнє китайське слово - 1-3 символи, тоді як середнє російське слово - багато, багато іншого.)


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

11
Звичайно. Ваша схема більш інформаційна, але вона не має важливої ​​функції, яку надає UTF-8. Взагалі, люди віддають перевагу безпеці, через що можливий UTF-8. Крім того, щоб дійсно довести, що ваша схема насправді є більш ефективною, ви хочете надати статистику за допомогою реального тексту. Ви можете виявити, що в більшості реальних текстів ваша схема економить дуже тривіальну суму, і, таким чином, заощадження не варто.
Gort the Robot

3
Ще одна важлива характеристика: Якщо немає вбудованої нульової кодової точки, в рядку немає вбудованих нулів.
Дедуплікатор

Для тайського сценарію потрібно дозволити 4 байти на друкований символ. Мало того, що вони пізно прийшли на вечірку, і так отримали велику пронумеровану кодову групу. Багато речей, які виглядають як один символ при друку, насправді складаються з трьох різних символів унікоду.
Джеймс Андерсон

@ qbt937: Як скористатися вашою схемою, як швидко сканувати, щоб дізнатись, чи містить одна рядок інша?
supercat

6

Офіційний спосіб повідомляє декодеру знати, коли він знаходиться в середині кортежу, і він знає пропускати байти (або йти назад), поки байт не починається з 0або 11; це запобігає значенню сміття, коли один байт пошкоджується.


3

Коротка відповідь, Ваша пропозиція не розрізняє перший байт і байти продовження.

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


2

Те, що не згадувалося, це те, що якщо у вас є правильна послідовність точок коду та покажчик, який гарантовано вказує на перший байт кодової точки, за допомогою UTF-8 ви можете легко знайти вказівник на перший байт попереднього кодового пункту (пропустіть усі байти, що починаються з 01xx xxxx). З допомогою кодування неможливо без потенційного вивчення всіх байт до початку рядка.

Розглянемо послідовності (2n + 2) байт

0xxxxxxx
n times (10xxxxxx, 10xxxxxx)
0xxxxxxx

і

n times (10xxxxxx, 10xxxxxx)
(10xxxxxx, 0xxxxxxx)

Якщо у вас є вказівник на перший байт першої кодової точки після цієї послідовності, ви повинні вивчити всі байти, щоб з’ясувати, чи є остання кодова точка 0xxxxxxx або (10xxxxxx, 0xxxxxxx).

Насправді існують більш ефективні схеми кодування, де перехід до попередньої кодової точки можна робити за постійний час, а покажчики на середину кодової точки можна фіксувати. Дозволити наступні коди:

X where X < 128
YX where 128 ≤ Y < 236, X < 128
ZYY where 236 ≤ Z < 256, 0 ≤ Y < 236. 

Якщо один з попередніх трьох байтів становить ≥ 236, то це початок послідовності з 3-х байт, тому що в жодній дійсній 3-байтній послідовності не може бути двох таких байтів. В іншому випадку, якщо один з попередніх двох байтів становить ≥ 128, то це початок послідовності з двох байтів. В іншому випадку попередній байт - це один байт <128.

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


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