Perché UTF-8 spreca diversi bit nella sua codifica


17

Secondo l' articolo di Wikipedia , UTF-8 ha questo formato:

Primo codice Ultimo codice Byte Byte 1 Byte 2 Byte 3 Byte 4
punto punto Usato
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 indica che questo bit viene utilizzato per selezionare il punto di codice.

In questo modo si sprecano due bit per ogni byte di continuazione e un bit nel primo byte. Perché UTF-8 non è codificato come il seguente?

Primo codice Ultimo codice Byte Byte 1 Byte 2 Byte 3
punto punto Usato
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 3FFF 2 10xxxxxx xxxxxxxx
U + 0800 U + 1FFFFF 3 110xxxxx xxxxxxxx xxxxxxxx

Si risparmia un byte quando il punto di codice è fuori dal piano multilingue di base o se il punto di codice è compreso nell'intervallo [U + 800, U + 3FFF].

Perché UTF-8 non è codificato in modo più efficiente?


3
cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt La codifica proposta è simile alla proposta FSS / UTF originale. Ken Thompson e Rob Pike volevano la proprietà di auto-sincronizzazione.
ninjalj

4
Inoltre, la tua codifica non sembra garantire che i valori del codice ASCII non compaiano in nessuna parte della rappresentazione per caratteri non ASCII. FSS / UTF e UTF-8 sono progettati per funzionare con programmi legacy (ad es. Quelli che usano ASCII NUL e barra (separatore di percorso) come separatori).
ninjalj,

Risposte:


26

Questo viene fatto in modo che tu possa rilevare quando ti trovi nel mezzo di una sequenza multi-byte. Quando guardi i dati UTF-8, sai che se vedi 10xxxxxx, sei nel mezzo di un carattere multibyte e dovresti eseguire il backup nello stream finché non vedi uno 0xxxxxxo 11xxxxxx. Usando il tuo schema, i byte 2 o 3 potrebbero facilmente finire con schemi come o 0xxxxxxxo11xxxxxx

Inoltre, tieni presente che la quantità di dati salvati varia completamente in base al tipo di dati stringa che stai codificando. Per la maggior parte del testo, anche asiatico, vedrai raramente, se mai, caratteri a quattro byte con testo normale. Inoltre, le stime ingenue della gente su come apparirà il testo sono spesso sbagliate. Ho testo localizzato per UTF-8 che include stringhe giapponesi, cinesi e coreane, ma in realtà è il russo a occupare più spazio. (Perché le nostre stringhe asiatiche hanno spesso caratteri romani intervallati da nomi propri, punteggiatura e simili e perché la parola cinese media è 1-3 caratteri mentre la parola russa media è molte, molte altre.)


Ma con me schema se inizi in una posizione nota per essere l'accattonaggio di un personaggio, allora puoi dire quanti byte ci sono nel personaggio e arrivare all'accattonaggio del personaggio successivo.
qbt937,

11
Sicuro. Il tuo schema è più denso di informazioni ma non ha una funzionalità importante che UTF-8 fornisce. In generale, le persone preferiscono la sicurezza, motivo per cui UTF-8 è possibile. Inoltre, per dimostrare davvero che il tuo schema è effettivamente più efficiente, ti consigliamo di fornire statistiche usando il testo reale. Potresti scoprire che nella maggior parte dei testi reali, il tuo schema consente di risparmiare un importo molto banale e quindi i risparmi non ne valgono la pena.
Gort il robot il

3
Un'altra caratteristica importante: se non ci sono punti di codice zero incorporati, non ci sono zero incorporati nella stringa.
Deduplicatore,

Per lo script tailandese è necessario consentire 4 byte per carattere stampato. Non solo sono arrivati ​​in ritardo alla festa e quindi hanno ottenuto un gruppo di codice numerato elevato. Molte cose che sembrano un singolo personaggio quando stampate sono in realtà composte da tre diversi caratteri Unicode.
James Anderson,

@ qbt937: usando il tuo schema, come si può scansionare rapidamente per scoprire se una stringa ne contiene un'altra?
supercat

6

Il modo ufficiale fa sapere al decoder quando si trova nel mezzo della tupla e sa saltare i byte (o tornare indietro) fino a quando il byte inizia con 0o 11; questo impedisce i valori di garbage quando un singolo byte viene danneggiato.


3

Risposta breve, la proposta non distingue tra il primo byte e i byte di continuazione.

Il modello di bit all'estremità superiore del primo byte indica con quanti byte viene creato il carattere effettivo. Questi schemi forniscono anche un certo riconoscimento degli errori durante l'analisi di una stringa. Se stai leggendo (apparentemente) il primo byte di un personaggio e ottieni 10xxxxxx, sai che non sei sincronizzato.


2

Ciò che non è stato menzionato è che se hai una sequenza corretta di punti di codice e un puntatore che è garantito per puntare al primo byte di un punto di codice, con UTF-8 puoi trovare facilmente il puntatore al primo byte del punto di codice precedente (salta tutti i byte che iniziano con 01xx xxxx). Con la tua codifica, è impossibile senza esaminare potenzialmente tutti i byte fino all'inizio della stringa.

Considera le sequenze di (2n + 2) byte

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

e

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

Se si dispone di un puntatore al primo byte del primo punto di codice dopo questa sequenza, è necessario esaminare tutti i byte per scoprire se l'ultimo punto di codice è 0xxxxxxx o (10xxxxxx, 0xxxxxxx).

Esistono in realtà schemi di codifica più efficienti, in cui è possibile passare al punto di codice precedente in tempo costante e è possibile correggere i puntatori al centro di un punto di codice. Consenti i seguenti codici:

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

Se uno dei tre byte precedenti è ≥ 236, allora è l'inizio di una sequenza di 3 byte, poiché non possono esserci due byte di questo tipo all'interno di una sequenza valida di 3 byte. Altrimenti, se uno dei due byte precedenti è ≥ 128, allora è l'inizio di una sequenza di due byte. Altrimenti, il byte precedente è un singolo byte <128.

La ricerca di una sottostringa diventa leggermente più difficile. È possibile che si desideri escludere zero byte in modo che una stringa contenga un byte zero solo se contiene un punto di codice zero.


Ciò che non è stato menzionato ... - non proprio come segue direttamente dall'osservazione fatta nella risposta di @ratchet maniaco.
Piotr Dobrogost
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.