Che cos'è Unicode, UTF-8, UTF-16?


395

Qual è la base per Unicode e perché è necessaria UTF-8 o UTF-16? Ho cercato questo su Google e cercato anche qui, ma non mi è chiaro.

In VSS quando si fa un confronto di file, a volte c'è un messaggio che dice che i due file hanno UTF diversi. Perché dovrebbe essere così?

Si prega di spiegare in termini semplici.


123
Sembra che tu abbia bisogno di leggere il minimo assoluto che ogni sviluppatore di software deve assolutamente conoscere positivamente su Unicode e set di caratteri ! È un'ottima spiegazione di ciò che sta succedendo.
Brian Agnew,

5
Questa FAQ dal sito ufficiale Unicode ha alcune risposte per te.
Nemanja Trifunovic,

4
@Giovanni: è un'introduzione molto bella, ma non è la fonte definitiva: salta parecchi dettagli (il che va bene per una panoramica / introduzione!)
Joachim Sauer,

5
L'articolo è eccezionale, ma presenta diversi errori e rappresenta UTF-8 in una luce un po 'conservatrice. Suggerisco di leggere utf8everywhere.org come supplemento.
Pavel Radzivilovsky,

2
Dai un'occhiata a questo sito Web: utf8everywhere.org
Vertexwahn,

Risposte:


550

Perché abbiamo bisogno di Unicode?

Agli albori (non troppo), tutto ciò che esisteva era ASCII. Questo andava bene, poiché tutto ciò che sarebbe mai stato necessario erano alcuni caratteri di controllo, punteggiatura, numeri e lettere come quelli in questa frase. Sfortunatamente, lo strano mondo odierno di intercomunicazione globale e social media non era previsto, e non è troppo insolito vedere inglese, inglese, spagnolo, ebraico, russo e ភាសាខ្មែរ nello stesso documento (spero di non aver rotto nessun vecchio i browser).

Ma per amor di sé, supponiamo che Joe Average sia uno sviluppatore di software. Insiste sul fatto che avrà sempre solo bisogno dell'inglese, e come tale vuole solo usare ASCII. Questo potrebbe andare bene per Joe l' utente , ma non va bene per Joe lo sviluppatore del software . Circa la metà del mondo usa caratteri non latini e l'uso dell'ASCII è probabilmente sconsiderato per queste persone, e per di più, sta chiudendo il suo software a un'economia grande e in crescita.

Pertanto, è necessario un set di caratteri comprensivo che includa tutte le lingue. Così è arrivato Unicode. Assegna a ogni carattere un numero univoco chiamato punto di codice . Un vantaggio di Unicode rispetto ad altri possibili set è che i primi 256 punti di codice sono identici a ISO-8859-1 , e quindi anche ASCII. Inoltre, la stragrande maggioranza dei caratteri comunemente usati è rappresentabile da soli due byte, in una regione chiamata Basic Multilingual Plane (BMP) . Ora è necessaria una codifica dei caratteri per accedere a questo set di caratteri e, man mano che la domanda si pone, mi concentrerò su UTF-8 e UTF-16.

Considerazioni sulla memoria

Quindi quanti byte danno accesso a quali caratteri in queste codifiche?

  • UTF-8:
    • 1 byte: ASCII standard
    • 2 byte: arabo, ebraico, la maggior parte degli script europei (in particolare il georgiano escluso )
    • 3 byte: BMP
    • 4 byte: tutti i caratteri Unicode
  • UTF-16:
    • 2 byte: BMP
    • 4 byte: tutti i caratteri Unicode

Vale la pena ricordare ora che i personaggi non inclusi nel BMP includono script antichi, simboli matematici, simboli musicali e caratteri cinesi / giapponesi / coreani (CJK) più rari .

Se lavorerai principalmente con caratteri ASCII, UTF-8 è sicuramente più efficiente in termini di memoria. Tuttavia, se lavori principalmente con script non europei, l'utilizzo di UTF-8 potrebbe essere fino a 1,5 volte meno efficiente in termini di memoria rispetto a UTF-16. Quando si ha a che fare con grandi quantità di testo, come pagine Web di grandi dimensioni o lunghi documenti di parole, ciò potrebbe influire sulle prestazioni.

Nozioni di base sulla codifica

Nota: se sai come sono codificati UTF-8 e UTF-16, passa alla sezione successiva per applicazioni pratiche.

  • UTF-8: per i caratteri ASCII standard (0-127), i codici UTF-8 sono identici. Ciò rende UTF-8 ideale se è richiesta la retrocompatibilità con il testo ASCII esistente. Altri caratteri richiedono da 2 a 4 byte. Questo viene fatto riservando alcuni bit in ciascuno di questi byte per indicare che fa parte di un carattere multi-byte. In particolare, il primo bit di ogni byte è 1evitare lo scontro con i caratteri ASCII.
  • UTF-16: per caratteri BMP validi, la rappresentazione UTF-16 è semplicemente il suo punto di codice. Tuttavia, per i caratteri non BMP UTF-16 introduce coppie surrogate . In questo caso, una combinazione di due porzioni a due byte viene mappata su un carattere non BMP. Queste porzioni a due byte provengono dall'intervallo numerico BMP, ma sono garantite dallo standard Unicode come non valide come caratteri BMP. Inoltre, poiché UTF-16 ha due byte come unità di base, è influenzato dall'endianness . Per compensare, un contrassegno di ordine di byte riservato può essere posizionato all'inizio di un flusso di dati che indica endianness. Pertanto, se si sta leggendo l'input UTF-16 e non è stata specificata alcuna endianness, è necessario verificarlo.

Come si può vedere, UTF-8 e UTF-16 non sono quasi compatibili tra loro. Quindi, se stai eseguendo I / O, assicurati di sapere quale codifica stai usando! Per ulteriori dettagli su queste codifiche, consultare le FAQ UTF .

Considerazioni pratiche sulla programmazione

Tipi di dati carattere e stringa: come vengono codificati nel linguaggio di programmazione? Se sono byte non elaborati, nel momento in cui si tenta di generare caratteri non ASCII, è possibile che si verifichino alcuni problemi. Inoltre, anche se il tipo di carattere si basa su un UTF, ciò non significa che le stringhe siano UTF appropriate. Possono consentire sequenze di byte illegali. In genere, dovrai utilizzare una libreria che supporti UTF, come ICU per C, C ++ e Java. In ogni caso, se desideri inserire / emettere qualcosa di diverso dalla codifica predefinita, dovrai prima convertirla.

Codifiche consigliate / predefinite / dominanti: quando viene data la scelta di quale UTF utilizzare, di solito è meglio seguire gli standard raccomandati per l'ambiente in cui si sta lavorando. Ad esempio, UTF-8 è dominante sul web e, dal momento che HTML5, è stata la codifica consigliata . Al contrario, gli ambienti .NET e Java sono basati su un tipo di carattere UTF-16. Confusamente (e in modo errato), spesso si fa riferimento alla "codifica Unicode", che di solito si riferisce alla codifica UTF dominante in un determinato ambiente.

Supporto per le librerie : le librerie in uso supportano un tipo di codifica. Quale? Supportano i casi d'angolo? Poiché la necessità è la madre dell'invenzione, le librerie UTF-8 generalmente supporteranno correttamente i caratteri a 4 byte, poiché possono comparire frequentemente caratteri 1, 2 e persino 3 byte. Tuttavia, non tutte le presunte librerie UTF-16 supportano correttamente coppie surrogate poiché si verificano molto raramente.

Conteggio dei caratteri: esistono caratteri combinati in Unicode. Ad esempio il punto di codice U + 006E (n) e U + 0303 (una tilde combinante) forma ñ, ma il punto di codice U + 00F1 forma ñ. Dovrebbero apparire identici, ma un semplice algoritmo di conteggio restituirà 2 per il primo esempio, 1 per quest'ultimo. Questo non è necessariamente sbagliato, ma potrebbe anche non essere il risultato desiderato.

Confronto per l'uguaglianza: A, А e Α sembrano uguali, ma sono rispettivamente latino, cirillico e greco. Hai anche casi come C e Ⅽ, uno è una lettera, l'altro un numero romano. Inoltre, dobbiamo considerare anche i personaggi di combinazione. Per ulteriori informazioni, vedi Caratteri duplicati in Unicode .

Coppie surrogate: si presentano abbastanza spesso su SO, quindi fornirò solo alcuni link di esempio:

Altri?:


11
Ottima risposta, grandi possibilità per la generosità ;-) Personalmente aggiungerei che alcuni sostengono UTF-8 come codifica universale dei caratteri , ma so che è un'opinione che non è necessariamente condivisa da tutti.
Joachim Sauer,

3
Ancora troppo tecnico per me in questa fase. Come viene memorizzata la parola ciao in un computer in UTF-8 e UTF-16?
FirstName LastName

1
Potresti espandere di più sul perché, ad esempio, il BMP impiega 3 byte in UTF-8? Avrei pensato che dal momento che il suo valore massimo è 0xFFFF (16 bit), ci sarebbero voluti solo 2 byte per accedere.
segna il

2
@mark Alcuni bit sono riservati a scopo di codifica. Per un punto di codice che richiede 2 byte in UTF-8, ci sono 5 bit riservati, lasciando solo 11 bit per selezionare un punto di codice. U + 07FF finisce per essere il punto di codice più alto rappresentabile in 2 byte.
DPenner1

1
BTW - ASCII definisce solo 128 punti di codice, usando solo 7 bit per la rappresentazione. È ISO-8859-1 / ISO-8859-15 che definisce 256 punti di codice e utilizza 8 bit per la rappresentazione. I primi 128 punti di codice in tutti questi 3 sono gli stessi.
Tuxdude,

67
  • Unicode
    • è un insieme di personaggi usati in tutto il mondo
  • UTF-8
    • una codifica dei caratteri in grado di codificare tutti i possibili caratteri (chiamati punti di codice) in Unicode.
    • l'unità di codice è di 8 bit
    • usa da una a quattro unità di codice per codificare Unicode
    • 00100100 per " $ " (uno a 8 bit); 11000010 10100010 per " ¢ " (due 8 bit); 11100010 10000010 10101100 per " " (tre 8 bit)
  • UTF-16
    • un'altra codifica di caratteri
    • l'unità di codice è a 16 bit
    • usa una o due unità di codice per codificare Unicode
    • 00000000 00100100 per " $ " (uno a 16 bit); 11011000 01010010 11011111 01100010 per " 𤭢 " (due 16 bit)

1
Breve e preciso
Aritra Chatterjee,

30

Unicode è uno standard abbastanza complesso. Non avere troppa paura, ma preparati per un po 'di lavoro! [2]

Poiché è sempre necessaria una risorsa credibile, ma il rapporto ufficiale è enorme, suggerisco di leggere quanto segue:

  1. Il minimo assoluto Ogni sviluppatore di software deve assolutamente conoscere positivamente Unicode e set di caratteri (senza scuse!) Un'introduzione di Joel Spolsky, CEO di Stack Exchange.
  2. Al BMP e oltre! Un tutorial di Eric Muller, poi direttore tecnico, poi vicepresidente presso il consorzio Unicode. (prime 20 diapositive e il gioco è fatto)

Una breve spiegazione:

I computer leggono i byte e le persone leggono i caratteri, quindi usiamo gli standard di codifica per mappare i caratteri ai byte. ASCII è stato il primo standard ampiamente utilizzato, ma copre solo il latino (7 bit / carattere può rappresentare 128 caratteri diversi). Unicode è uno standard con l'obiettivo di coprire tutti i possibili personaggi del mondo (può contenere fino a 1.114.112 caratteri, il che significa 21 bit / carattere massimo. L'attuale Unicode 8.0 specifica 120.737 caratteri in totale, e questo è tutto).

La differenza principale è che un carattere ASCII può adattarsi a un byte (8 bit), ma la maggior parte dei caratteri Unicode non può. Quindi vengono utilizzati moduli / schemi di codifica (come UTF-8 e UTF-16), e il modello del personaggio va così:

Ogni personaggio ha una posizione enumerata da 0 a 1.114.111 (esadecimale: 0-10FFFF) chiamato punto di codice .
Un modulo di codifica mappa un punto di codice su una sequenza di unità di codice. Un'unità di codice è il modo in cui si desidera organizzare i caratteri in memoria, unità a 8 bit, unità a 16 bit e così via. UTF-8 utilizza da 1 a 4 unità da 8 bit e UTF-16 utilizza 1 o 2 unità da 16 bit, per coprire l'intero Unicode di 21 bit max. Le unità usano i prefissi in modo che i limiti dei caratteri possano essere individuati e più unità significano più prefissi che occupano i bit. Quindi, sebbene UTF-8 usi 1 byte per lo script latino, ha bisogno di 3 byte per gli script successivi all'interno del Piano multilingue di base, mentre UTF-16 usa 2 byte per tutti questi. E questa è la loro principale differenza.
Infine, uno schema di codifica (come UTF-16BE o UTF-16LE) mappa (serializza) una sequenza di unità di codice in una sequenza di byte.

carattere:
punto di codice π : U + 03C0
forme di codifica (unità di codice):
      UTF-8: CF 80
      UTF-16: 03C0
schemi di codifica (byte):
      UTF-8: CF 80
      UTF-16BE: 03 C0
      UTF-16LE: C0 03

Suggerimento: una cifra esadecimale rappresenta 4 bit, quindi un numero esadecimale a due cifre rappresenta un byte
Guarda anche le mappe dei piani in Wikipedia per avere un'idea del layout del set di caratteri


19

Inizialmente, Unicode doveva avere una codifica a 16 bit a larghezza fissa (UCS-2). I primi utenti di Unicode, come Java e Windows NT, costruirono le loro librerie attorno a stringhe a 16 bit.

Successivamente, l'ambito di Unicode è stato ampliato per includere caratteri storici, che richiederebbero oltre i 65.536 punti di codice supportati da una codifica a 16 bit. Per consentire la rappresentazione dei caratteri aggiuntivi su piattaforme che avevano utilizzato UCS-2, fu introdotta la codifica UTF-16. Usa "coppie surrogate" per rappresentare i personaggi nei piani supplementari.

Nel frattempo, molti vecchi software e protocolli di rete utilizzavano stringhe a 8 bit. UTF-8 è stato realizzato in modo che questi sistemi potessero supportare Unicode senza dover utilizzare caratteri ampi. È retrocompatibile con ASCII a 7 bit.


3
Vale la pena notare che Microsoft fa ancora riferimento a UTF-16 come Unicode, aggiungendo confusione. I due non sono gli stessi.
Mark Ransom,

15

Questo articolo spiega tutti i dettagli http://kunststube.net/encoding/

SCRIVERE AL BUFFER

se scrivi su un buffer di 4 byte, simbolo con codifica UTF8, il tuo binario sarà simile al seguente:

00000000 11100011 10000001 10000010

se scrivi su un buffer di 4 byte, simbolo con codifica UTF16, il tuo binario sarà simile al seguente:

00000000 00000000 00110000 01000010

Come puoi vedere, a seconda della lingua che utilizzeresti nei tuoi contenuti, ciò influenzerà la tua memoria di conseguenza.

ad es. per questo particolare simbolo: la codifica UTF16 è più efficiente poiché abbiamo 2 byte di riserva da usare per il simbolo successivo. Ma ciò non significa che devi usare UTF16 per l'alfabeto giapponese.

LETTURA DAL BUFFER

Ora se vuoi leggere i byte sopra, devi sapere in quale codifica è stato scritto e decodificarlo correttamente.

ad es. se decodifichi questo: 00000000 11100011 10000001 10000010 nella codifica UTF16, finirai con non

Nota: la codifica e Unicode sono due cose diverse. Unicode è la grande (tabella) con ogni simbolo mappato su un punto di codice univoco. es. il simbolo (lettera) ha un (punto di codice) : 30 42 (esadecimale). La codifica, d'altra parte, è un algoritmo che converte i simboli in un modo più appropriato, quando si archivia su hardware.

30 42 (hex) - > UTF8 encoding - > E3 81 82 (hex), which is above result in binary.

30 42 (hex) - > UTF16 encoding - > 30 42 (hex), which is above result in binary.

inserisci qui la descrizione dell'immagine


12

Unicode è uno standard che mappa i caratteri in tutte le lingue su un particolare valore numerico chiamato Punti di codice . La ragione per cui lo fa è che consente di codificare diversi utilizzando lo stesso set di punti di codice.

UTF-8 e UTF-16 sono due di queste codifiche. Prendono punti di codice come input e li codificano utilizzando una formula ben definita per produrre la stringa codificata.

La scelta di una codifica particolare dipende dalle tue esigenze. Codifiche diverse hanno requisiti di memoria diversi e, a seconda dei caratteri con cui si avrà a che fare, è necessario scegliere la codifica che utilizza le sequenze minime di byte per codificare quei caratteri.

Per dettagli più approfonditi su Unicode, UTF-8 e UTF-16, puoi consultare questo articolo,

Ciò che ogni programmatore dovrebbe sapere su Unicode


9

Perché Unicode? Perché ASCII ha solo 127 caratteri. Quelli da 128 a 255 differiscono in diversi paesi, ecco perché ci sono tabelle codici. Quindi hanno detto che abbiamo un massimo di 1114111 caratteri. Quindi, come si memorizza il punto di codice più alto? Dovrai memorizzarlo usando 21 bit, quindi utilizzerai un DWORD con 32 bit con 11 bit sprecati. Quindi se usi un DWORD per memorizzare un carattere Unicode, è il modo più semplice perché il valore nel tuo DWORD corrisponde esattamente al punto di codice. Ma gli array DWORD sono ovviamente più grandi degli array WORD e ovviamente anche più grandi degli array BYTE. Ecco perché non c'è solo utf-32, ma anche utf-16. Ma utf-16 significa un flusso WORD e una WORD ha 16 bit, quindi come può il punto di codice più alto 1114111 inserirsi in una WORD? Non può! Quindi misero ogni cosa più in alto di 65535 in un DWORD che chiamano una coppia surrogata. Tale coppia di surrogati sono due PAROLE e possono essere rilevate osservando i primi 6 bit. E che dire di utf-8? È un array di byte o un flusso di byte, ma come può il punto di codice più alto 1114111 inserirsi in un byte? Non può! Ok, quindi hanno inserito anche un DWORD giusto? O forse una PAROLA, giusto? Quasi giusto! Hanno inventato sequenze utf-8, il che significa che ogni punto di codice superiore a 127 deve essere codificato in una sequenza di 2 byte, 3 byte o 4 byte. Wow! Ma come possiamo rilevare tali sequenze? Bene, tutto fino a 127 è ASCII ed è un singolo byte. Ciò che inizia con 110 è una sequenza a due byte, ciò che inizia con 1110 è una sequenza a tre byte e ciò che inizia con 11110 è una sequenza a quattro byte. I bit rimanenti di questi cosiddetti "startbytes" appartengono al punto di codice. Ora, a seconda della sequenza, devono seguire i seguenti byte. Un byte seguente inizia con 10, i bit rimanenti sono 6 bit di bit di payload e appartengono al punto di codice. Concatena i bit di payload dello startbyte e dei seguenti byte / e avrai il punto di codice. Questa è tutta la magia di utf-8.


3
utf-8 esempio di segno € (Euro) decodificato in sequenza a 3 byte utf-8: E2 = 11100010 82 = 10000010 AC = 10101100 Come puoi vedere, E2 inizia con 1110 quindi questa è una sequenza di tre byte Come puoi vedere , 82 e AC inizia con 10, quindi questi sono i seguenti byte Ora concateniamo i "bit di payload": 0010 + 000010 + 101100 = 10000010101100 che è decimale 8364 Quindi 8364 deve essere il codice per il segno € (Euro).
luminoso

5

ASCII - Il software alloca solo 8 byte di bit in memoria per un dato carattere. Funziona bene con caratteri inglesi e adottati (prestiti come la facciata) poiché i loro valori decimali corrispondenti scendono al di sotto di 128 nel valore decimale. Esempio di programma C.

UTF-8 - Il software alloca da 1 a 4 byte variabili a 8 bit per un dato carattere. Cosa significa qui per variabile? Diciamo che stai inviando il carattere 'A' attraverso le tue pagine HTML nel browser (HTML è UTF-8), il corrispondente valore decimale di A è 65, quando lo converti in decimale diventa 01000010. Ciò richiede solo 1 byte , La memoria di 1 byte è allocata anche per caratteri inglesi speciali adottati come 'ç' in una facciata di parole. Tuttavia, quando si desidera memorizzare caratteri europei, sono necessari 2 byte, quindi è necessario UTF-8. Tuttavia, quando si scelgono i caratteri asiatici, sono necessari almeno 2 byte e un massimo di 4 byte. Allo stesso modo, le Emoji richiedono da 3 a 4 byte. UTF-8 risolverà tutte le tue esigenze.

UTF-16 assegnerà un minimo di 2 byte e un massimo di 4 byte per carattere, non assegnerà 1 o 3 byte. Ogni personaggio è rappresentato in 16 bit o 32 bit.

Allora perché esiste UTF-16? Inizialmente, Unicode era a 16 bit e non a 8 bit. Java ha adottato la versione originale di UTF-16.

In poche parole, non hai bisogno di UTF-16 ovunque a meno che non sia già stato adottato dalla lingua o dalla piattaforma su cui stai lavorando.

Il programma Java richiamato dai browser Web utilizza UTF-16 ma il browser Web invia caratteri utilizzando UTF-8.


"Non hai bisogno di UTF-16 da nessuna parte a meno che non sia già stato adottato dalla lingua o dalla piattaforma": questo è un buon punto ma ecco un elenco non inclusivo: JavaScript, Java, .NET, SQL NCHAR, SQL NVARCHAR , VB4, VB5, VB6, VBA, VBScript, NTFS, API di Windows….
Tom Blodget,

2

UTF significa acronimo di Unicode Transformation Format. Fondamentalmente nel mondo di oggi ci sono script scritti in centinaia di altre lingue, formati non coperti dall'ASCII di base usato in precedenza. Quindi, UTF è nato.

UTF-8 ha capacità di codifica dei caratteri e la sua unità di codice è di 8 bit mentre quella per UTF-16 è di 16 bit.

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.