UTF-8, UTF-16 e UTF-32


487

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?


36
Guarda questo video se sei interessato a come funziona Unicode youtube.com/watch?v=MijmeoH9LT4

1
Il video si concentra su UTF-8, e sì spiega bene come funziona la codifica a lunghezza variabile ed è principalmente compatibile con i computer che leggono o scrivono solo ASCII a lunghezza fissa. I ragazzi Unicode erano intelligenti quando progettavano la codifica UTF-8.
Min

1
Ho creato uno strumento online per la conversione e il confronto.
Amit Kumar Gupta,

1
UTF-8 è lo standard di fatto nella maggior parte dei software moderni per i file salvati . Più specificamente, è la codifica più utilizzata per HTML e file di configurazione e traduzione (Minecraft, ad esempio, non accetta altre codifiche per tutte le sue informazioni di testo). UTF-32 è veloce per la rappresentazione della memoria interna e UTF-16 è un po ' deprecato , attualmente utilizzato solo in Win32 per motivi storici ( UTF-16 era a lunghezza fissa quando Windows 95 era una cosa)
Kotauskas,

@VladislavToncharov UTF-16 non è mai stata una codifica a lunghezza fissa. Lo stai confondendo con UCS-2.

Risposte:


373

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.


165
Vantaggio UTF-32: non è necessario decodificare i dati memorizzati nel punto di codice Unicode a 32 bit, ad es. Gestione dei caratteri. Il punto di codice è già disponibile proprio nell'array / vettore / stringa.
richq

22
È anche più facile analizzare se (il cielo ti aiuta) devi reimplementare la ruota.
Paul McMillan,

24
Bene, UTF-8 ha un vantaggio nei trasferimenti di rete: non è necessario preoccuparsi dell'endianità poiché si trasferiscono i dati un byte alla volta (anziché 4).
Tim Čas,

30
@richq Non è possibile eseguire la gestione carattere per carattere in UTF-32, poiché il punto di codice non corrisponde sempre a un carattere.
hamstergene,

4
Vantaggio UTF-32: la manipolazione delle stringhe è forse più veloce rispetto all'equivalente utf-8
Wes

332

In breve:

  • UTF-8: codifica a larghezza variabile, retrocompatibile con ASCII. I caratteri ASCII (da U + 0000 a U + 007F) prendono 1 byte, i punti di codice U + 0080 a U + 07FF prendono 2 byte, i punti di codice U + 0800 ... U + FFFF prendono 3 byte, i punti di codice U + 10000 ... U + 10FFFF prendere 4 byte. Buono per il testo inglese, non così buono per il testo asiatico.
  • UTF-16: codifica a larghezza variabile. I punti di codice da U + 0000 a U + FFFF prendono 2 byte, i punti di codice da U + 10000 a U + 10FFFF prendono 4 byte. Male per il testo inglese, buono per il testo asiatico.
  • UTF-32: codifica a larghezza fissa. Tutti i punti di codice richiedono quattro byte. Un enorme maiale di memoria, ma veloce su cui operare. Utilizzato raramente.

In lungo: vedi Wikipedia: UTF-8 , UTF-16 e UTF-32 .


65
@spurrymoses: mi riferisco rigorosamente alla quantità di spazio occupato dai byte di dati. UTF-8 richiede 3 byte per carattere asiatico, mentre UTF-16 richiede solo 2 byte per carattere asiatico. Questo non è davvero un grosso problema, dal momento che i computer hanno tonnellate di memoria in questi giorni rispetto alla quantità media di testo memorizzato nella memoria di un programma.
Adam Rosenfield,

12
UTF-32 non viene più usato raramente ... su osx e linux ha come wchar_timpostazione predefinita 4 byte. gcc ha un'opzione -fshort-wcharche riduce la dimensione a 2 byte, ma rompe la compatibilità binaria con le librerie std.
vigilia,

9
@PandaWood ofcource UTF-8 può codificare qualsiasi personaggio! Ma hai confrontato il requisito di memoria con quello per UTF-16? Sembra che manchi il punto!
Ustaman Sangat,

16
Se qualcuno dovesse dire che UTF-8 non è "così buono per il testo asiatico" nel contesto di tutti i formati di codifica, inclusi quelli che non possono codificare Unicode, sarebbe ovviamente sbagliato. Ma quello non è il contesto. Il contesto dei requisiti di memoria deriva dal fatto che la domanda (e la risposta) sta confrontando UTF-8, UTF-16 e UTF-32, che codificheranno tutti il ​​testo asiatico ma utilizzeranno quantità diverse di memoria / archiviazione. Ne consegue che la loro relativa bontà sarebbe naturalmente interamente nel contesto dei requisiti di memoria. "Not so good"! = "Non buono".
Paul Gregory,

5
@McGafter: Beh, certo che c'è. Se vuoi l'affidabilità, vai direttamente alla bocca del cavallo al consorzio Unicode . Vedere il capitolo 2.5 per una descrizione delle codifiche UTF- *. Ma per ottenere una comprensione semplice e di alto livello delle codifiche, trovo che gli articoli di Wikipedia siano una fonte molto più accessibile.
Adam Rosenfield,

116
  • 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


35
UTF8 è in realtà da 1 a 6 byte.
Urkle,

6
@Urkle è tecnicamente corretto perché la mappatura dell'intera gamma di UTF32 / LE / BE include U-00200000 - U-7FFFFFFF anche se Unicode v6.3 termina con U-0010FFFF incluso. Ecco la ripartizione bella di come ENC / DEC 5 e 6 utf8 byte: lists.gnu.org/archive/html/help-flex/2005-01/msg00030.html

4
il backup di questi con parti di riferimento pertinenti e le loro fonti?
n611x007,

20
@Urkle No, UTF-8 non può essere 5 o 6 byte. I punti di codice Unicode sono limitati a 21 bit, il che limita UTF-8 a 4 byte. (Potresti ovviamente estendere il principio di UTF-8 per codificare interi grandi arbitrari, ma non sarebbe Unicode.) Vedi RFC 3629.
rdb

11
Citando Wikipedia: Nel novembre 2003, UTF-8 è stato limitato da RFC 3629 per abbinare i vincoli della codifica dei caratteri UTF-16: proibire esplicitamente i punti di codice corrispondenti ai caratteri surrogato alto e basso rimuoveva più del 3% delle sequenze a tre byte e terminando con U + 10FFFF ha rimosso oltre il 48% delle sequenze a quattro byte e tutte le sequenze a cinque e sei byte.
Adam Calvet Bohl,

79

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.


12
Non è corretto affermare che Unicode assegna un numero intero univoco a ciascun simbolo grafico . Assegna tale valore a ciascun punto di codice, ma alcuni punti di codice sono caratteri di controllo invisibili e alcuni simboli grafici richiedono più punti di codice per rappresentare.
tchrist

15
@tchrist: sì, è impreciso. Il problema è che per spiegare con precisione Unicode, è necessario scrivere migliaia di pagine. Speravo di far capire il concetto di base per spiegare la differenza tra codifiche
jalf

@jalf lol giusto, quindi sostanzialmente per spiegare Unicode dovresti scrivere le specifiche Unicode Core
Justin Ohms

@tchrist Più specificamente, puoi costruire simboli cinesi partendo dalle primitive fornite (ma sono nello stesso grafico, quindi finirai per usare una quantità irreale di spazio - disco o RAM - per codificarli) invece di usare il quelli integrati.
Kotauskas,

44

Unicode è uno standard e su UTF-x puoi pensare come un'implementazione tecnica per alcuni scopi pratici:

  • UTF-8 - " ottimizzato per le dimensioni ": più adatto per dati basati sui caratteri latini (o ASCII), richiede solo 1 byte per carattere ma le dimensioni aumentano di conseguenza varietà di simboli (e nel peggiore dei casi potrebbero crescere fino a 6 byte per carattere)
  • UTF-16 - " balance ": sono necessari almeno 2 byte per carattere, il che è sufficiente per l'insieme esistente delle lingue principali con dimensioni fisse su di esso per facilitare la gestione dei caratteri (ma la dimensione è ancora variabile e può crescere fino a 4 byte per carattere )
  • UTF-32 - " performance ": consente l'utilizzo di semplici algoritmi come risultato di caratteri a dimensione fissa (4 byte) ma con svantaggio della memoria

«Lingue tradizionali» non così tradizionale in molte parti del mondo ^^
tuxayo

2
UTF-16 è in realtà ottimizzato per dimensioni per caratteri non ASCII. Perché dipende davvero da quali lingue verranno utilizzate.
tuxayo,

@tuxayo è assolutamente d'accordo, vale la pena notare set di personaggi Hanzi e Kanji per la parte asiatica del mondo.
recato il

Dovrebbe essere la risposta migliore. Questo è troppo corretto per essere sepolto qui.
Michal Štein,

28

Ho provato a dare una semplice spiegazione nel mio post sul blog .

UTF-32

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.

UTF-16

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

UTF-8

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

Un piccolo esempio in cui UTF-16 è effettivamente migliore di UTF-8:

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.


19

UTF-8

  • non ha alcun concetto di ordine byte
  • utilizza tra 1 e 4 byte per carattere
  • ASCII è un sottoinsieme compatibile di codifica
  • la sincronizzazione automatica totale, ad esempio un byte rilasciato da qualsiasi punto di uno stream, corromperà al massimo un singolo carattere
  • praticamente tutte le lingue europee sono codificate in due byte o meno per carattere

UTF-16

  • deve essere analizzato con ordine di byte noto o leggendo un segno di ordine di byte (BOM)
  • utilizza 2 o 4 byte per carattere

UTF-32

  • ogni carattere è di 4 byte
  • deve essere analizzato con ordine di byte noto o leggendo un segno di ordine di byte (BOM)

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.


Come funziona la "sincronizzazione automatica" in UTF-8? Puoi fornire esempi per caratteri da 1 e 2 byte?
Koray Tugay,

2
@KorayTugay Stringhe di byte più brevi valide non vengono mai utilizzate in caratteri più lunghi. Ad esempio, ASCII è compreso nell'intervallo 0-127, il che significa che tutti i caratteri a un byte hanno la forma 0xxxxxxxin binario. Tutti i caratteri a due byte iniziano 110xxxxxcon un secondo byte di 10xxxxxx. Supponiamo quindi che il primo carattere di un carattere a due byte sia perso. Non appena vedi 10xxxxxxsenza 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 .
Chris,

1
se hai l'offset a un personaggio, hai l'offset a quel personaggio - utf8, utf16 o utf32 funzioneranno allo stesso modo in quel caso; cioè sono tutti ugualmente bravi nell'accesso casuale mediante offset dei caratteri in una matrice di byte. L'idea che utf32 sia migliore nel contare i caratteri di utf8 è anche completamente falsa. Un punto di codice (che non è lo stesso di un carattere che, di nuovo, non è lo stesso di un grafema .. sigh), ha una larghezza di 32 bit in utf32 e tra 8 e 32 bit in utf8, ma un carattere può comprendere più punti di codice, che distrugge il grande vantaggio che la gente afferma che utf32 ha rispetto a utf8.
Più chiaro il

14

Ho fatto alcuni test per confrontare le prestazioni del database tra UTF-8 e UTF-16 in MySQL.

Velocità di aggiornamento

UTF-8

Inserisci qui la descrizione dell'immagine

UTF-16

Inserisci qui la descrizione dell'immagine

Inserisci velocità

Inserisci qui la descrizione dell'immagine

Inserisci qui la descrizione dell'immagine

Elimina velocità

Inserisci qui la descrizione dell'immagine

Inserisci qui la descrizione dell'immagine


14

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.


Perché dovrei voler calcolare la lunghezza della stringa durante lo sviluppo di siti Web? C'è qualche vantaggio nello scegliere UTF-8 / UTF-16 nello sviluppo web?
Morfidon,

"Il vantaggio è che puoi facilmente calcolare la lunghezza della stringa" Se definisci la lunghezza per il numero di punti di codice, allora sì, puoi semplicemente dividere la lunghezza del byte per 4 per ottenerla con UTF-32. Questa non è una definizione molto utile, tuttavia: potrebbe non essere correlata al numero di caratteri. Inoltre, la normalizzazione può alterare il numero di punti di codice nella stringa. Ad esempio, la parola francese "été" può essere codificata in almeno 4 modi diversi, con 3 lunghezze distinte di punti di codice.

UTF-16 è probabilmente più veloce di UTF-8, ma anche nessuna perdita di memoria come fa UTF-32.
Michal Štein,

6

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.


Probabilmente, molto più importante dei requisiti di spazio è il fatto che UTF-8 è immune all'endianità. UTF-16 e UTF-32 dovranno inevitabilmente affrontare problemi di endianness, in cui UTF-8 è semplicemente un flusso di ottetti.
Indispensabile dal

2

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.


o semplicemente usa UTF-8 come predefinito in quanto è diventato lo standard di fatto e scopri se un nuovo sistema lo supporta o meno. in caso contrario, puoi tornare a questo post.
robotik,

-2

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


Non sono sicuro, perché mi suggerisci, che l'utilizzo di UTF-16 o UTF-32 dovesse supportare il testo non inglese. UTF-8 può gestirlo bene. E ci sono anche caratteri non ASCII nel testo inglese. Come un non-joiner a larghezza zero. O un trattino. Temo che questa risposta non aggiunga molto valore.
Indispensabile dal

Questa domanda è soggetta a downvoting perché UTF-8 è ancora comunemente usato nei file HTML anche se la maggior parte dei caratteri sono caratteri a 3 byte in UTF-8,
Ṃųỻịgǻňạcểơửṩ

Il supporto @IInspectable non è la migliore formulazione, promuovere o un supporto migliore sarebbe più accurato
robotik,

Inviare una pagina come utf8everywhere.org non è ciò che farei in una risposta SO.
Michal Štein,
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.