Quali sono le differenze tra UTF-8, UTF-16 e UTF-32?
Comprendo che memorizzeranno tutti Unicode e che ciascuno utilizza un diverso numero di byte per rappresentare un personaggio. C'è un vantaggio nella scelta l'uno rispetto all'altro?
Quali sono le differenze tra UTF-8, UTF-16 e UTF-32?
Comprendo che memorizzeranno tutti Unicode e che ciascuno utilizza un diverso numero di byte per rappresentare un personaggio. C'è un vantaggio nella scelta l'uno rispetto all'altro?
Risposte:
UTF-8 ha un vantaggio nel caso in cui i caratteri ASCII rappresentino la maggior parte dei caratteri in un blocco di testo, poiché UTF-8 li codifica in 8 bit (come ASCII). È anche vantaggioso che un file UTF-8 contenente solo caratteri ASCII abbia la stessa codifica di un file ASCII.
UTF-16 è migliore dove ASCII non è predominante, poiché utilizza principalmente 2 byte per carattere. UTF-8 inizierà a utilizzare 3 o più byte per i caratteri di ordine superiore in cui UTF-16 rimane a soli 2 byte per la maggior parte dei caratteri.
UTF-32 coprirà tutti i possibili caratteri in 4 byte. Questo lo rende piuttosto gonfio. Non riesco a pensare a nessun vantaggio nell'usarlo.
In breve:
wchar_t
impostazione predefinita 4 byte. gcc ha un'opzione -fshort-wchar
che riduce la dimensione a 2 byte, ma rompe la compatibilità binaria con le librerie std.
UTF-8 è variabile da 1 a 4 byte.
UTF-16 è variabile 2 o 4 byte.
UTF-32 è fisso a 4 byte.
Nota: UTF-8 può richiedere da 1 a 6 byte con l'ultima convenzione: https://lists.gnu.org/archive/html/help-flex/2005-01/msg00030.html
Unicode definisce un unico enorme set di caratteri, assegnando un valore intero univoco a ciascun simbolo grafico (che è una semplificazione importante, e non è in realtà vero, ma è abbastanza vicino ai fini di questa domanda). UTF-8/16/32 sono semplicemente modi diversi per codificarlo.
In breve, UTF-32 utilizza valori a 32 bit per ciascun carattere. Ciò consente loro di utilizzare un codice a larghezza fissa per ogni carattere.
UTF-16 utilizza 16 bit per impostazione predefinita, ma ciò ti dà solo 65k possibili caratteri, che non è abbastanza vicino per l'intero set Unicode. Quindi alcuni personaggi usano coppie di valori a 16 bit.
E UTF-8 utilizza valori a 8 bit per impostazione predefinita, il che significa che i primi 127 valori sono caratteri a byte singolo a larghezza fissa (il bit più significativo viene utilizzato per indicare che questo è l'inizio di una sequenza multi-byte, lasciando 7 bit per il valore attuale del carattere). Tutti gli altri caratteri sono codificati come sequenze fino a 4 byte (se la memoria serve).
E questo ci porta ai vantaggi. Qualsiasi carattere ASCII è direttamente compatibile con UTF-8, quindi per l'aggiornamento di app legacy, UTF-8 è una scelta comune ed ovvia. In quasi tutti i casi, utilizzerà anche meno memoria. D'altra parte, non è possibile fornire garanzie sulla larghezza di un personaggio. Può contenere 1, 2, 3 o 4 caratteri di larghezza, il che rende difficile la manipolazione delle stringhe.
UTF-32 è opposto, utilizza la maggior parte della memoria (ogni carattere ha una larghezza fissa di 4 byte), ma d'altra parte, sai che ogni personaggio ha questa lunghezza precisa, quindi la manipolazione delle stringhe diventa molto più semplice. È possibile calcolare il numero di caratteri in una stringa semplicemente dalla lunghezza in byte della stringa. Non puoi farlo con UTF-8.
UTF-16 è un compromesso. Permette alla maggior parte dei caratteri di adattarsi a un valore a 16 bit di larghezza fissa. Quindi finché non hai simboli cinesi, note musicali o altri, puoi presumere che ogni personaggio abbia una larghezza di 16 bit. Utilizza meno memoria di UTF-32. Ma è in qualche modo "il peggio di entrambi i mondi". Utilizza quasi sempre più memoria di UTF-8 e non evita ancora il problema che affligge UTF-8 (caratteri a lunghezza variabile).
Infine, è spesso utile scegliere semplicemente ciò che supporta la piattaforma. Windows utilizza UTF-16 internamente, quindi su Windows, questa è la scelta ovvia.
Linux varia un po ', ma generalmente usano UTF-8 per tutto ciò che è conforme Unicode.
Risposta così breve: tutte e tre le codifiche possono codificare lo stesso set di caratteri, ma rappresentano ciascun carattere come sequenze di byte diverse.
Unicode è uno standard e su UTF-x puoi pensare come un'implementazione tecnica per alcuni scopi pratici:
Ho provato a dare una semplice spiegazione nel mio post sul blog .
richiede 32 bit (4 byte) per codificare qualsiasi carattere. Ad esempio, per rappresentare il punto di codice del carattere "A" usando questo schema, dovrai scrivere 65 in un numero binario a 32 bit:
00000000 00000000 00000000 01000001 (Big Endian)
Se dai un'occhiata più da vicino, noterai che i sette bit più a destra sono in realtà gli stessi bit quando usi lo schema ASCII. Ma poiché UTF-32 è uno schema a larghezza fissa , dobbiamo collegare tre byte aggiuntivi. Ciò significa che se abbiamo due file che contengono solo il carattere "A", uno è codificato ASCII e l'altro è codificato UTF-32, la loro dimensione sarà di 1 byte e 4 byte di conseguenza.
Molte persone pensano che poiché UTF-32 utilizza una larghezza fissa a 32 bit per rappresentare un punto di codice, UTF-16 ha una larghezza fissa di 16 bit. SBAGLIATO!
In UTF-16 il punto di codice potrebbe essere rappresentato in 16 bit o in 32 bit. Quindi questo schema è un sistema di codifica a lunghezza variabile. Qual è il vantaggio rispetto all'UTF-32? Almeno per ASCII, la dimensione dei file non sarà 4 volte l'originale (ma comunque due volte), quindi non siamo ancora compatibili con le versioni precedenti ASCII.
Dato che 7 bit sono sufficienti per rappresentare il carattere "A", ora possiamo usare 2 byte anziché 4 come UTF-32. Sembrerà che:
00000000 01000001
Hai indovinato bene. In UTF-8 il punto di codice potrebbe essere rappresentato usando 32, 16, 24 o 8 bit e, come sistema UTF-16, anche questo è un sistema di codifica a lunghezza variabile.
Finalmente possiamo rappresentare "A" nello stesso modo in cui lo rappresentiamo usando il sistema di codifica ASCII:
01001101
Considera la lettera cinese "語" - la sua codifica UTF-8 è:
11101000 10101010 10011110
Mentre la sua codifica UTF-16 è più breve:
10001010 10011110
Per capire la rappresentazione e come viene interpretata, visita il post originale.
UTF-8 sarà il più efficiente in termini di spazio a meno che la maggior parte dei personaggi provenga dallo spazio caratteri CJK (cinese, giapponese e coreano).
UTF-32 è la soluzione migliore per l'accesso casuale mediante offset dei caratteri in un array di byte.
0xxxxxxx
in binario. Tutti i caratteri a due byte iniziano 110xxxxx
con un secondo byte di 10xxxxxx
. Supponiamo quindi che il primo carattere di un carattere a due byte sia perso. Non appena vedi 10xxxxxx
senza un precedente 110xxxxxx
, puoi determinare con certezza che un byte è stato perso o danneggiato e scartare quel carattere (o richiederlo nuovamente da un server o altro) e andare avanti fino a quando non vedi di nuovo un primo byte valido .
Ho fatto alcuni test per confrontare le prestazioni del database tra UTF-8 e UTF-16 in MySQL.
In UTF-32 tutti i caratteri sono codificati con 32 bit. Il vantaggio è che puoi facilmente calcolare la lunghezza della stringa. Lo svantaggio è che per ogni carattere ASCII si sprecano altri tre byte.
In UTF-8 i caratteri hanno una lunghezza variabile, i caratteri ASCII sono codificati in un byte (otto bit), la maggior parte dei caratteri speciali occidentali sono codificati in due byte o tre byte (ad esempio € è tre byte) e possono essere utilizzati caratteri più esotici a quattro byte. Il chiaro svantaggio è che a priori non è possibile calcolare la lunghezza della stringa. Ma occorrono molti meno byte per codificare il testo in alfabeto latino (inglese), rispetto a UTF-32.
UTF-16 ha anche una lunghezza variabile. I caratteri sono codificati in due byte o quattro byte. Non vedo davvero il punto. Ha lo svantaggio di essere di lunghezza variabile, ma non ha il vantaggio di risparmiare spazio quanto UTF-8.
Di questi tre, chiaramente UTF-8 è il più diffuso.
A seconda del proprio ambiente di sviluppo, potrebbe non essere possibile scegliere quale codifica verrà utilizzata internamente dal tipo di dati della stringa.
Ma per l'archiviazione e lo scambio di dati utilizzerei sempre UTF-8, se avete la scelta. Se disponi principalmente di dati ASCII, ciò ti fornirà la minima quantità di dati da trasferire, pur potendo codificare tutto. L'ottimizzazione per il minimo I / O è la strada da percorrere su macchine moderne.
Come accennato, la differenza è principalmente la dimensione delle variabili sottostanti, che in ogni caso diventano più grandi per consentire la rappresentazione di più caratteri.
Tuttavia, i caratteri, la codifica e le cose sono maledettamente complicati (inutilmente?), Quindi è necessario un grande collegamento per riempire più in dettaglio:
http://www.cs.tut.fi/~jkorpela/chars.html#ascii
Non aspettarti di capire tutto, ma se non vuoi avere problemi in un secondo momento vale la pena di imparare il più possibile, il più presto possibile (o semplicemente convincere qualcun altro a risolverlo per te).
Paolo.
In breve, l'unico motivo per utilizzare UTF-16 o UTF-32 è supportare rispettivamente script non inglesi e antichi.
Mi chiedevo perché qualcuno avrebbe scelto di avere una codifica non UTF-8 quando è ovviamente più efficiente per scopi web / di programmazione.
Un malinteso comune - il numero suffisso NON è un'indicazione della sua capacità. Tutti supportano l'intero Unicode, solo che UTF-8 può gestire ASCII con un singolo byte, quindi è PIÙ efficiente / meno corruttibile per la CPU e su Internet.
Qualche buona lettura: http://www.personal.psu.edu/ejp10/blogs/gotunicode/2007/10/which_utf_do_i_use.html e http://utf8everywhere.org