UTF-8 (abbreviazione di Universal Character Set Transformation Format - 8 bits ) è una codifica di caratteri per computer progettata per codificare l'insieme di caratteri del "repertorio di caratteri codificati universale", originariamente sviluppato da ISO nello standard internazionale ISO/IEC 10646 , ora pienamente compatibile con lo standard Unicode , pur rimanendo compatibile con lo standard ASCII limitato all'inglese di base, ma ampiamente utilizzato da decenni.
UTF-8 è utilizzato dall'82,2% dei siti web in dicembre 2014, 87,6% nel 2016, 90,5% nel 2017, 93,1% in febbraio 2019 e quasi il 95,2% in ottobre 2020. Per sua natura, UTF-8 è sempre più utilizzato su Internet e nei sistemi che necessitano di scambiare informazioni. È anche la codifica più utilizzata nei sistemi GNU , Linux e compatibili per gestire i testi e le loro traduzioni nel modo più semplice possibile in tutti i sistemi di scrittura e tutti gli alfabeti del mondo.
UTF-8 è un "formato di trasformazione" originariamente dal lavoro per lo standard ISO/IEC 10646 , ovvero UTF-8 definisce una codifica per qualsiasi punto di codice scalare ( carattere astratto o "non carattere") dall'Universal Character Set ( UCS ) directory. Questa directory è ora comune allo standard ISO/IEC 10646 (dalla sua revisione 1) e allo standard Unicode (dalla sua versione 1.1).
UTF-8 è ufficialmente definito nello standard ISO/IEC 10646 dalla sua adozione in un emendamento pubblicato nel 1996. È stato anche descritto nello standard Unicode e fa parte di questo standard dalla versione 3.0 pubblicata nel 2000. Nel 1996 è stato pubblicato il RFC 2044 (" UTF-8, un formato di trasformazione di ISO 10646 ") al fine di fornire una specifica accessibile di UTF-8 e iniziare la sua standardizzazione all'interno della Internet Engineering Task Force (IETF). Questa RFC è stata rivista nel 1998 ( RFC 2279) e infine nel 2003 ( RFC 3629), quest'ultima versione rendendo UTF-8 uno degli standard di Internet (STD 63).
Tecnicamente, ciò comporta la codifica di caratteri Unicode sotto forma di sequenze da uno a quattro codepoint di un byte ciascuno. Lo standard Unicode definisce, tra le altre cose, un insieme (o directory) di caratteri. Ogni carattere è identificato in questo set da un intero indice chiamato anche “ code point ”. Ad esempio il carattere “€” ( euro ) è l'8365 ° carattere della directory Unicode, il suo indice, o code point, è quindi 8364 (0x20AC) (si comincia a contare da 0).
La directory Unicode può contenere oltre un milione di caratteri, che è troppo grande per essere codificato come un singolo byte (limitato a valori compresi tra 0 e 255). Lo standard Unicode definisce quindi metodi standardizzati per la codifica e la memorizzazione di questo indice sotto forma di una sequenza di byte: UTF-8 è uno di questi, insieme a UTF-16 , UTF-32 e le loro varie varianti.
La caratteristica principale di UTF-8 è che è retrocompatibile con lo standard ASCII, vale a dire che qualsiasi carattere ASCII è codificato in UTF-8 sotto forma di un singolo byte, identico al codice ASCII. . Ad esempio "A" (A maiuscola) ha il codice ASCII 65 (0x41) ed è codificato in UTF-8 dal byte 65. Ogni carattere il cui punto di codice è maggiore di 127 (0x7F) (carattere non ASCII) è il codice da 2 a 4 byte . Il carattere “€” (euro) è codificato ad esempio su 3 byte : 226, 130 e 172 (0xE2, 0x82 e 0xAC).
Il numero (valore scalare) di ogni punto di codice nell'Universal Character Set (UCS) è dato dalla norma ISO/IEC 10646 che assegna un punto di codice ad ogni carattere valido e ne consente la codifica assegnando un valore scalare identico al punto di codice ; questo standard è incluso nello standard Unicode (che utilizza la stessa directory dalla versione 1.1).
Tutti i " code points " da U+0000 a U+D7FF e da U+E000 a U+10FFFF sono rappresentabili in UTF-8 - anche quelli assegnati ai "non caratteri" ( non carattere ) e tutti quelli non ancora assegnati - e solo quelli. L'unico codice rileva valido nello spazio UCS e che non debba essere rappresentato in UTF-8 sono quelli assegnati ai " mezze Codepoints " ( surrogati in inglese), perché non sono rappresentabili in un modo. Biunivoca nella codifica UTF-16 e non sono nemmeno caratteri da soli: a differenza di altri punti di codice, i mezzi codici quindi non hanno un " valore scalare " definito.
I dot code aventi un valore scalare da 0 a 127 (U + 0000 code point U + 007F, assegnati ai caratteri dell'insieme codificati su 7 bit in ASCII) sono codificati su un byte di cui il bit più significativo è zero.
Gli altri punti di codice (assegnati o meno a caratteri) aventi un valore scalare maggiore di 127 (tranne quelli a cui sono assegnati "mezzi codici" che non sono essi stessi caratteri) sono codificati su più byte, ciascuno con i propri. bit più significativo: i bit più significativi del primo byte della sequenza codificata formano una sequenza di 1 di lunghezza pari al numero totale di byte (almeno 2) utilizzati per l'intera sequenza seguiti da uno 0 e i successivi byte richiesti hanno i loro due bit più significativi impostati a 10.
Caratteri codificati | Rappresentazione binaria UTF-8 | Primo byte valido (esadecimale) | Senso |
---|---|---|---|
Da U + 0000 a U + 007F | 0 xxxxxxx | da 00 a 7F | 1 byte, codifica 7 bit |
Da U + 0080 a U + 07FF | 11 0 xxxxx 10 xxxxxx | Da C2 a DF | 2 byte, codifica 11 bit |
Da U + 0800 a U + FFFF | 111 0 xxxx 10 xxxxxx 10 xxxxxx | da E0 a EF | 3 byte, codifica 16 bit |
Da U + 10000 a U + 10FFFF | 1111 0 xxx 10 xxxxxx 10 xxxxxx 10 xxxxxx | Da F0 a F4 | 4 byte, codifica 21 bit |
Questo principio potrebbe essere esteso a otto byte per un singolo punto di codice (per rappresentare punti di codice fino a 42 bit), ma l'attuale versione standardizzata di UTF-8 imposta il limite a quattro.
La codifica vieta la rappresentazione dei punti di codice riservati ai semicodici (che non hanno un valore scalare definito, al fine di preservare la compatibilità con UTF-16 che non consente nemmeno loro di essere rappresentati). Tuttavia, autorizza la rappresentazione dei punti di codice assegnati ai non caratteri (anche se la loro presenza è vietata in un testo conforme).
genere | Personaggio |
Punto di codice (esadecimale) |
Valore scalare | Codifica UTF-8 | ||
---|---|---|---|---|---|---|
decimale | binario | binario | esadecimale | |||
Controllo | [NO] | U + 0000 | 0 | 0 | 0 0000000 | 00 |
[NOI] | U + 001F | 31 | 1111 | 0 0011111 | 1F | |
Testo | [SP] | U + 0020 | 32 | 100000 | 0 0100000 | 20 |
A | U + 0041 | 65 | 100.0001 | 0 100.0001 | 41 | |
~ | U + 007E | 126 | 111 1110 | 0 1111110 | 7E | |
Controllo | [DELLA] | U + 007F | 127 | 111 1111 | 0 1111111 | 7F |
[TASTIERA] | U + 0080 | 128 | 000 1000 0000 | 110 000 10 10 000 000 | C2 80 | |
[APC] | U + 009F | 159 | 000 1001 1111 | 110 000 10 10 011 111 | C2 9FA | |
Testo | [NBSP] | U + 00A0 | 160 | 000 1010 0000 | 110 000 10 10 100 000 | C2 LA0 |
é | U + 00E9 | 233 | 000 1110 1001 | 110 000 11 10 101 001 | C3 LA9 | |
߿ | U + 07FF | 2047 | 111 1111 1111 | 110 111 11 10 111 111 | DF BF | |
ࠀ | U + 0800 | 2048 | 1000 0000 0000 | 1110 0000 10 1000 00 10 000000 | E0 A0 80 | |
€ | U + 20AC | 8 364 | 100000 10101100 | 1110 0010 10 0000 10 10 101100 | E2 82 AC | |
| U + D7FF | 55.295 | 1101 0111 1111 1111 | 1110 1101 10 0111 11 10 111111 | ED 9F BF | |
mezzo codetto | U + D800 | (Niente) | (codifica vietata) | |||
U + DFFF | ||||||
Uso privato | [] | U + E000 | 57.344 | 1110 0000 0000 0000 | 1110 1110 10 0000 00 10 0000000 | EE 80 80 |
[] | U + F8FF | 63.743 | 1111 1000 1111 1111 | 1110 1111 10 1000 11 10 111111 | EF A3 BF | |
Testo | U + F900 | 63 744 | 1111 1001 0000 0000 | 1110 1111 10 1001 00 10 000 000 | EF A4 80 | |
﷏ | U + FDCF | 64 975 | 1111 1101 1100 1111 | 1110 1111 10 1101 11 10 001111 | MI SI B7 8 FA | |
Non personaggi | U + FDD0 | 64 976 | 1111 1101 1101 0000 | 1110 1111 10 1101 11 10 010000 | EF B7 90 | |
U + FDEF | 65.007 | 1111 1101 1110 1111 | 1110 1111 10 1101 11 10 101111 | EF B7 AF | ||
Testo | صلے | U + DFF0 | 65.008 | 1111 1101 1111 0000 | 1110 1111 10 1101 11 10 110000 | EF B7 B0 |
U + FFFD | 65.533 | 1111 1111 1111 1101 | 1110 1111 10 1111 11 10 111101 | EF BF BD | ||
Non personaggi | U + FFFE | 65.534 | 1111 1111 1111 1110 | 1110 1111 10 1111 11 10 111110 | EF BF BE | |
U + FFFF | 65.535 | 1111 1111 1111 1111 | 1110 1111 10 1111 11 10 111111 | EF BF BF | ||
Testo | ? | U + 10.000 | 65.536 | 1 0000 0000 0000 0000 | 11 110 000 10 01 0000 10 0000 00 10 000000 | F0 90 80 80 |
? | U + 1D11E | 119.070 | 1 1101 0001 0001 1110 | 11 110 000 10 01 1101 10 0001 00 10 011 110 | F0 9D 84 9E | |
? | U + 1FFFD | 131.069 | 1 1111 1111 1111 1101 | 11110 000 10 01 1111 10 1111 11 10 111 101 | F0 9F BF BD | |
Non personaggi | U + 1FFFE | 131.070 | 1 1111 1111 1111 1110 | 11110 000 10 01 1111 10 1111 11 10 111 110 | F0 9F BF BE | |
U + 1FFFF | 131.071 | 1 1111 1111 1111 1111 | 11 110 000 10 01 1111 10 1111 11 10 111111 | F0 9F BF BF | ||
Testo | ? | U + 20.000 | 131.072 | 10 0000 0000 0000 0000 | 11 110 000 10 10 0000 10 0000 00 10 000000 | F0 A0 80 80 |
? | U + 2FFFD | 196.605 | 10 1111 1111 1111 1101 | 11110 000 10 10 1111 10 1111 11 10 111 101 | F0 AF BF BD | |
Non personaggi | U + 2FFFE | 196.606 | 10 1111 1111 1111 1110 | 11110 000 10 10 1111 10 1111 11 10 111 110 | F0 AF BF BE | |
U + 2FFFF | 196.607 | 10 1111 1111 1111 1111 | 11 110 000 10 10 1111 10 1111 11 10 111111 | F0 AF BF BF | ||
... altri piani riservati ... | ||||||
Speciali | ? | U + E0000 | 917.504 | 1110 0000 0000 0000 0000 | 11110 011 10 10 0000 10 0000 00 10 000000 | F3 A0 80 80 |
? | U + EFFFD | 983.037 | 1110 1111 1111 1111 1101 | 11110 011 10 10 1111 10 1111 11 10 111101 | F3 AF BF BD | |
Non personaggi | U + EFFFE | 983.038 | 1110 1111 1111 1111 1110 | 11110 011 10 10 1111 10 1111 11 10 111110 | F3 AF BF BE | |
U + EFFFF | 983.039 | 1110 1111 1111 1111 1111 | 11110 011 10 10 1111 10 1111 11 10 111111 | F3 AF BF BF | ||
Uso privato | [?] | U + F0000 | 983.040 | 1111 0000 0000 0000 0000 | 11110 011 10 11 0000 10 0000 00 10 000000 | F3 B0 80 80 |
[ ] | U + FFFFD | 1.048.573 | 1111 1111 1111 1111 1101 | 11110 011 10 11 1111 10 1111 11 10 111101 | F3 BF BF BD | |
Non personaggi | U + FFFFE | 1.048.574 | 1111 1111 1111 1111 1110 | 11110 011 10 11 1111 10 1111 11 10 111110 | F3 BF BF BE | |
U + FFFFF | 1.048.575 | 1111 1111 1111 1111 1111 | 11110 011 10 11 1111 10 1111 11 10 111111 | F3 BF BF BF | ||
Uso privato | [?] | U + 100.000 | 1.048.576 | 1 0000 0000 0000 0000 0000 | 11110 100 10 00 0000 10 0000 00 10 000000 | F4 80 80 80 |
[?] | U + 10FFFD | 1.114.109 | 1 0000 1111 1111 1111 1101 | 11110 100 10 00 1111 10 1111 11 10 111101 | F4 8F BF BD | |
Non personaggi | U + 10FFFE | 1.114.110 | 1 0000 1111 1111 1111 1110 | 11110 100 10 00 1111 10 1111 11 10 111110 | F4 8F BF BE | |
U + 10FFFF | 1,114,111 | 1 0000 1111 1111 1111 1111 | 11110 100 10 00 1111 10 1111 11 10 111111 | F4 8F BF BF |
In qualsiasi stringa di caratteri codificata in UTF-8, notiamo che:
Il più grande punto di assegnabile codice valido per un carattere valido , non privato è U + EFFFD nel 15 ° piano (non è ancora assegnato, ma può diventare in futuro), ma UTF-8 può anche essere utilizzato, in modo standard, per rappresentare qualsiasi carattere valido per uso privato (in uno dei tre intervalli da U + E000 a U + F8FF, da U + F0000 a U + FFFFD e da U + 100000 a U + 10FFFD) .
L'accettazione o meno di caratteri non caratteri o di uso privato è lasciata alle applicazioni o ai protocolli di trasporto del testo. Tuttavia, i non caratteri non sono normalmente accettati nei testi strettamente conformi allo standard Unicode o allo standard ISO/IEC 10646 .
Alcune applicazioni impongono ulteriori restrizioni sui punti di codice utilizzabili (ad esempio, gli standard HTML e XML vietano, in qualsiasi documento conforme a queste specifiche, la presenza della maggior parte dei caratteri di controllo tra U + 0000 e U + 001F e tra U + 0080 e U + 009F, al di fuori del controllo a schede U + 0009 considerato un carattere vuoto e vietano anche i non caratteri ).
Ogni punto di codice è sempre rappresentato esattamente dalla stessa sequenza binaria, qualunque sia la sua posizione relativa nel testo, e queste sequenze sono autosincronizzate sulla posizione indivisa dei punti di codice significativi (qui i byte: possiamo sempre sapere se un byte inizia o meno un sequenza binaria efficace); questa codifica consente quindi algoritmi di ricerca di testo veloce, come l' algoritmo di Boyer-Moore .
Questo non è sempre il caso delle codifiche contestuali (che generalmente utilizzano la compressione dei dati , ad esempio SCSU definita nella nota tecnica opzionale UTS standard n. 6 che integra lo standard Unicode) e che possono richiedere la lettura del testo completamente dall'inizio., né le codifiche basate su più di una singola variabile di stato (o che incorporano codici di ridondanza aggiuntivi); nella migliore delle ipotesi alcune di queste codifiche possono richiedere l'uso di complessi algoritmi di risincronizzazione, spesso basati su euristiche che possono fallire o portare a false interpretazioni se il testo non viene letto dall'inizio (es. BOCU -1).
Principio e unicità della codificaNella tabella sopra, vediamo che il carattere "€" si trova al punto di codice U + 20AC, sia in decimale 8364, sia in binario: 100.000 10101100.
Quest'ultimo numero ha cifre binarie significative, quindi sono necessari almeno 14 bit per codificare il carattere "€". Lo standard presentato sopra richiede in realtà tre byte per rappresentare questi caratteri.
Con quattro byte a disposizione, sarebbe possibile posizionare secondo questo standard fino a 21 bit , quindi in particolare rappresentare il carattere “€” per 00000 00 100000 10101100, aggiungendovi 7 zeri iniziali . Tuttavia, lo standard impone che un programma che decodifica UTF-8 non debba accettare stringhe di byte inutilmente lunghe come in questo esempio, per motivi di sicurezza (evitare l'uso di test di sottostringa troppo tolleranti). Quindi “€” sarà codificato: 11100010 100000110 10101100, ma la codifica 11110000 100000010 100000010 10101100, desunta dalla rappresentazione di “€” su 21 bit , seppur univoca, non deve essere utilizzata.
Tale forma più lunga del necessario è chiamata overlong in inglese . Tali moduli (inizialmente autorizzati in vecchie specifiche prima che venissero successivamente standardizzati dalla RFC iniziale pubblicata dall'X/Open Consortium , poi parallelamente dallo standard ISO 10646 e dallo standard Unicode) sono vietati e devono essere trattati come non validi.
La codifica è predittiva e permette sempre di trovare la posizione del primo byte di una sequenza che rappresenta un code point, dal valore di un qualsiasi byte e dalla lettura di un numero limitato di byte adiacenti, nelle due direzioni di lettura (si sarà sempre il byte stesso o il primo eleggibile in uno dei byte adiacenti da 1 a 3 ).
Tali sequenze si dicono mal formate . (Vedi il riferimento sopra, in particolare la seconda tabella nella clausola di conformità D36 dello standard o l'articolo Unicode ).
Sono invece autorizzati punti di codice riservati (non ancora assegnati ai caratteri) (anche se l'interpretazione dei caratteri può rimanere ambigua): spetta alle applicazioni decidere se tali caratteri sono accettabili o meno, sapendo che gli stessi le applicazioni continueranno probabilmente ad essere utilizzate anche se queste posizioni sono state assegnate negli standard Unicode e ISO 10646 a nuovi caratteri pienamente validi.
Allo stesso modo, altri punti di codice assegnati in modo permanente ad altri " non caratteri " sono vietati nei testi conformi alla ISO / IEC 10646 o allo standard Unicode : ad esempio da U + x FFFE a U + x FFFF (dove x indica un numero di piano esadecimale da da 0 a 10). Ma rimangono codificabili e decodificabili come tali in UTF-8 (i non caratteri sono disponibili per applicazioni che possono farne uso all'interno di API interne, ad esempio come codici intermedi necessari per l'implementazione di determinati processi.).
La limitazione dello spazio rappresentazione di punti di codice solo inferiore o uguale a U + 10FFFF (esclusi i punti di codice assegnati ai punti mezzo-code ) non sempre seguito:
Un testo in US-ASCII è codificato in modo identico in UTF-8 (quando non viene utilizzata la BOM ).
Poiché un carattere è diviso in una sequenza di byte (non parole multibyte), non ci sono problemi di endianness ( endianness inglese).
Per la maggior parte dei linguaggi di scrittura latina, file di dati digitali o codici sorgente di programmi, o molti protocolli di comunicazione testuale (come FTP , HTTP o MIME ), che utilizzano caratteri ampiamente (o talvolta solo in parti) US-ASCII, UTF-8 richiede meno byte di UTF-16 o UTF-32 .
Molte tecniche di programmazione per computer valide con caratteri uniformi a byte singolo rimangono valide con UTF-8, tra cui:
Questa è una codifica autosincronizzante (leggendo un singolo byte sappiamo se è il primo di un carattere o meno).
I punti di codice sono rappresentati in UTF-8 da sequenze di byte di dimensioni variabili (così come in UTF-16), il che rende più complicate alcune operazioni su stringhe di punti di codice: calcolo del numero di punti di codice; posizionamento ad una data distanza (espressa in numero di punti di codice) in un file di testo e in generale qualsiasi operazione che richieda l'accesso al punto di codice di posizione N in una catena.
Una dimensione variabile dei caratteri di una stringa impedisce l'uso di algoritmi efficienti in termini di confronti di stringhe, come l'algoritmo di Knuth-Morris-Pratt e quindi penalizza fortemente l'elaborazione di dati di massa come nei database. Questo problema è però più legato ad aspetti di standardizzazione che di codifica.
Per le lingue che utilizzano molti caratteri al di fuori di US-ASCII , UTF-8 occupa molto più spazio. Ad esempio, gli ideogrammi comuni utilizzati nei testi in lingue asiatiche come il cinese o il giapponese ( kanji , per esempio) utilizzano 3 byte in UTF-8 contro 2 byte in UTF-16.
In generale, le scritture che utilizzano molti punti di codice di valore uguale o maggiore di U + 0800 occupano più memoria che se fossero codificate con UTF-16 (UTF-32 sarà più efficiente solo per testi che utilizzano principalmente scritture. vecchio o raro codificato al di fuori del piano multilingue di base, cioè da U + 10000, ma può anche rivelarsi utile localmente in certi processi per semplificare gli algoritmi, perché i caratteri lì hanno sempre una dimensione fissa, convertendo input o output dati da o verso UTF-8 o UTF-16 sono banali).
Con il suo sistema di codifica, era possibile rappresentare un codice in modi diversi in UTF-8, il che potrebbe porre un problema di sicurezza: un programma scritto male può accettare un certo numero di rappresentazioni UTF-8, normalmente non valide secondo la RFC 3629 e nelle specifiche (ora equivalenti tra loro) pubblicate da ISO 10646 e Unicode; ma questo non era il caso secondo la specifica originale, che permetteva di convertirli in un singolo carattere.
Pertanto, un software che rileva determinate stringhe di caratteri (per evitare iniezioni SQL , ad esempio) potrebbe fallire nel suo compito (non è più così se viene verificata la conformità della codifica con la definizione rigorosa e standardizzata di UTF-8. tutti).
Prendiamo un esempio da un caso reale di un virus che attacca i server HTTP sul Web nel 2001 ( (en) Crypto-Gram: 15 luglio 2000 Microsoft IIS e PWS Vulnerabilità di attraversamento della directory estesa Unicode Microsoft IIS 4.0 / 5.0 Vulnerabilità di attraversamento della directory Web ) . Una sequenza da rilevare potrebbe essere “/../” rappresentata in ASCII ( a fortiori in UTF-8) dai byte “ 2F 2E 2E 2F ” in notazione esadecimale . Tuttavia, un modo errato per codificare questa stringa in UTF-8 sarebbe " 2F C0 AE 2E 2F ", chiamato anche forma troppo lunga . Se il software non è scritto accuratamente per rifiutare questa catena, ad esempio mettendola in forma canonica , si apre una potenziale violazione della sicurezza. Questo attacco è chiamato attraversamento di directory .
Il software che accetta il testo codificato in UTF-8 è stato schermato per rifiutare sistematicamente queste forme lunghe perché non conformi allo standard: o l'intero testo viene rifiutato; ma a volte le sequenze non valide vengono sostituite da un carattere di sostituzione (di solito U + FFFD se l'applicazione accetta ed elabora questo carattere normalmente; a volte un punto interrogativo o il carattere di controllo della sostituzione SUB U + 001A di ASCII, che può porre altri problemi di compatibilità); meno spesso, queste sequenze proibite vengono eliminate silenziosamente (cosa molto poco consigliata).
UTF-8 può rappresentare solo il carattere di controllo null (U + 0000) con un singolo byte null, il che pone problemi di compatibilità con l'elaborazione di stringhe che non codificano separatamente la loro lunghezza effettiva perché questo byte null non rappresenta quindi nessun carattere ma il fine della stringa (caso molto comune nel linguaggio C o C++ e nelle API dei sistemi operativi). Se un carattere nullo deve essere memorizzato in un testo su tali sistemi, sarà necessario ricorrere ad un sistema di escape, specifico per questa lingua o sistema prima di codificare in UTF-8 il testo così trasformato. In pratica, nessun testo valido dovrebbe contenere questo carattere. Un'altra soluzione consiste nell'utilizzare una delle sequenze vietate nella codifica standard UTF-8 per codificare il carattere con questa sequenza; ma il testo così codificato non sarà conforme alla codifica UTF-8 standard, anche se la codifica così modificata rimane un formato di trasformazione universale conforme (che, tuttavia, non dovrebbe essere designato come "UTF-8"). Vedere la sezione seguente sulle varianti non standard basate su UTF-8.
L'utilizzo di UTF8, come qualsiasi codifica a passo variabile, in un database pone molteplici problemi di prestazioni.
Le operazioni di confronto (=,>, <, BETWEEN, LIKE ...), l'ordinamento (ORDER BY), il raggruppamento (GROUP BY), come le operazioni di deduplicazione (DISTINCT) basate sulla semantica delle informazioni, non possono essere gestite direttamente in UTF8 .
Infatti, per stringhe di caratteri composte dallo stesso numero di lettere (ad esempio CHAR (8)), il numero di byte può essere diverso (in particolare a causa dei caratteri diacritici: accenti, legature...), gli algoritmi utilizzati devono, per per la maggior parte, eseguire un allineamento prima di poter operare, il che comporta un costo aggiuntivo di lavorazione non trascurabile.
Ad esempio il DBMS MySQL/MariaDB ha scelto di rappresentare i caratteri delle stringhe presentate come UTF8 utilizzando sistematicamente 3 byte per carattere. Le conseguenze sono le seguenti: triplicare il volume dei dati e dividere per tre la lunghezza potenziale delle chiavi di indice rispetto alla codifica ASCII, e allungare i tempi di esecuzione per confronti, ordinamenti, raggruppamenti o deduplica. La stringa viene infine restituita in formato UTF8 dopo aver ripulito i byte non necessari.
Altri DBMS come Microsoft SQL Server hanno scelto di comprimere il supporto UTF8 inserendo i caratteri aggiuntivi in una codifica a 2 byte, basata su UNICODE sfruttando gli spazi lasciati vuoti dalla specifica. Lo sforzo aggiuntivo per la traduzione in UTF8 risiede solo nella ricodifica dei caratteri codificati su 2 byte e nell'espansione di quelli codificati su 3.
UTF-8 è stato inventato da Kenneth Thompson durante una cena con Rob Pike in girosettembre 1992. Chiamato quindi FSS-UTF , è stato immediatamente utilizzato nel sistema operativo Plan 9 su cui stavano lavorando. Un vincolo da risolvere era quello di codificare i caratteri null e '/' come in ASCII e che nessun byte che codifica un altro carattere abbia lo stesso codice. Pertanto, i sistemi operativi UNIX potrebbero continuare a cercare questi due caratteri in una stringa senza adattamento del software.
FSS-UTF è stato oggetto di uno standard X/Open preliminare del 1993 che è stato proposto all'ISO. Quest'ultimo lo adottò come parte dello standard ISO/IEC 10646 con il nome prima di UTF-2, poi infine UTF-8.
Grafico che mostra l'uso di UTF-8 (azzurro) che supera le altre principali codifiche di caratteri di testo sul Web. Nel 2010 la prevalenza di UTF-8 era di circa il 50%, ma nel 2016 era più simile al 90%. |
Statistiche che riflettono le tecnologie utilizzate sui siti Web determinate da tecniche di riconoscimento per diversi modelli, inclusi elementi HTML, tag HTML specifici (come il tag "generator meta", il codice JavaScript, il codice CSS, la struttura degli URL del sito, collegamenti fuori sito, intestazioni HTTP ad esempio cookie, risposte HTTP a determinate richieste come la compressione.
Statistiche basate su un campione dei primi 10 milioni di siti web secondo Alexa. Il totale non raggiunge il 100% perché alcuni server utilizzano più di una tecnologia. |
Fonte w3techs |
La codifica originale FSS-UTF aveva lo scopo di sostituire la codifica multibyte UTF-1 inizialmente proposta dalla ISO 10646. Questa codifica inizialmente permissiva consentiva diverse rappresentazioni binarie per lo stesso carattere (questo era proibito nella versione standardizzata nella RFC pubblicata dalla X / Open Consortium e approvato da Kenneth Thompson).
Inoltre potrebbe (in una versione preliminare non mantenuta) codificare tutti i caratteri il cui valore di code point comprendeva fino a 32 bit definendo un ottavo tipo di byte (in sequenze comprendenti fino a 6 byte ), al posto dei 7 tipi di byte infine mantenuti per codificare (in sequenze comprendenti anche fino a 6 byte ) solo il codice punta fino a 31 bit nella versione iniziale di UTF-8 (pubblicata dal Consorzio X/Open con il nome FSS-UTF, poi proposta dal comitato tecnico della ISO 10646 come proposta “UTF-2” quindi ancora in concorrenza con la proposta “UTF-1”, fino a che la proposta UTF-2 non viene mantenuta e adotta il nome UTF-8 già mantenuto e utilizzato in X/Open e Piano 9).
Questa codifica UTF-8 è stata ulteriormente ridotta quando Unicode e ISO 10646 convenuto di allocare caratteri solo nei primi 17 piani al fine di mantenere la compatibilità con UTF-16 indefinitamente (senza dover modificare), limitando sequenze fino 'a 4 byte solo e utilizzando solo i primi 5 dei 7 tipi di byte (il che ha reso necessario definire come nuovi valori di byte non validi e alcune sequenze di byte comunque valide singolarmente).
L'IETF ora richiede UTF-8 è supportato di default (e non semplicemente come estensione supportata) da tutti i nuovi protocolli di comunicazione di Internet (pubblicati nella sua RFC numerata) che scambiano testo (i protocolli più vecchi, invece, non sono stati modificati rendere obbligatorio questo supporto, ma solo esteso se possibile, supportarlo facoltativamente, se questo produce incompatibilità o introduce nuovi rischi per la sicurezza: è il caso dei protocolli Internet largamente utilizzati come DNS , HTTP , FTP , Telnet e HTML nelle sue versioni iniziali quindi non ancora standardizzata da W3C e ISO).
È diventato fondamentale, soprattutto nei principali software di comunicazione web e oggi nei sistemi operativi:
Tuttavia, le varianti di UTF-8 (basate sulle possibilità di codifica della versione iniziale senza restrizioni) hanno continuato ad essere utilizzate (in particolare nell'implementazione della serializzazione di stringhe Java) per consentire la codifica come escape multibyte di determinati caratteri ASCII riservati normalmente codificati in un singolo byte (ad esempio il carattere null).
Inoltre, alcuni sistemi utilizzano stringhe illimitate: ad esempio Java (e altri linguaggi comprese le librerie di manipolazione delle stringhe in C, PHP, Perl, ecc.) rappresentano caratteri con unità di codifica su 16 bit (il che rende possibile memorizzare stringhe utilizzando UTF -16 codifica, ma senza i vincoli di validità imposti da UTF-16 riguardo a valori vietati e pairing nell'ordine dei "mezzi codici" o surrogati ); in questo caso le unità di codifica vengono trattate come valori binari ed è necessario serializzarle singolarmente (indipendentemente dalla loro eventuale interpretazione come caratteri o come mezzi punti del codice). In questo caso, ogni unità di codifica a 16 bit che rappresenta un "carattere" (non vincolato) viene serializzata sotto forma di sequenze comprendenti fino a 3 byte ciascuna e alcuni byte vietati dall'implementazione (ad esempio i caratteri nulli o la barra delle frazioni ' /' in un filesystem o altri caratteri a byte singolo in altri protocolli) sono codificati come sequenze di escape a doppio byte nessuna delle quali è zero, semplicemente usando il principio di codifica della prima specifica di FSS-UTF (prima di quella trattenuta dall'X / Open Consortium nella sua RFC iniziale in cui queste fughe erano specificamente vietate e sono rimaste tali).
Prima dell'adozione della proposta UTF-2 mantenuta per UTF-8, esisteva anche una variante UTF-1, in cui non erano possibili più codifiche, ma richiedeva una codifica/decodifica più difficile per tenere conto della posizione di ciascun byte. una serie di valori "magici".
Queste varianti non dovrebbero essere chiamate "UTF-8".
Una di queste varianti non standard è stata però oggetto di una successiva standardizzazione (in alternativa all'UTF-16 e utilizzando coppie di "semicodici" codificate ciascuna su 3 byte, ovvero 6 byte in tutto invece di 4 con UTF-8): vedi CESU-8 .
Esempio di una variante utilizzata in JavaAd esempio, le API di integrazione di Java virtual machine (per JNI, Java Native Interface o per la serializzazione di classi precompilate), che consentono lo scambio di stringhe Java non vincolate sotto forma di sequenze di byte (per manipolarle, utilizzare o produrre per codice nativo, o per l'archiviazione come file nativo codificato in stringhe di byte), hanno il suffisso "UTFChars" o "UTF", ma questa codifica specifica per Java non è UTF-8 (la documentazione di Sun si riferisce ad essa come UTF modificato , ma alcuni documenti JNI più vecchi si riferiscono ancora erroneamente a questa codifica come UTF-8 , che ha prodotto alcune anomalie comportamentali di alcune librerie JNI native, in particolare con le API di sistema. piattaforme native precedenti che non supportano nativamente le codifiche dei caratteri su 8 bit ), perché:
Di conseguenza:
Questi processi possono essere inefficienti per interfacciare grandi quantità di testo perché richiedono l'allocazione di buffer di memoria aggiuntivi per poi interfacciarsi in codice nativo con interfacce di sistema o di rete che accettano solo lo standard UTF-8.
Tuttavia JNI fornisce anche un'API binaria più efficiente che consente di utilizzare direttamente UTF-16, in grado di interfacciarsi direttamente con i protocolli di rete e le interfacce di sistema (es. API di Windows) che supportano UTF-16, senza richiedere alcuna allocazione di memoria aggiuntiva per la transcodifica (solo la conformità check può essere necessario, principalmente per verificare nel testo codificato il corretto abbinamento del mezzo codice o surrogato , che Java (come anche altri linguaggi di programmazione) permette di manipolare senza limiti di validità nelle proprie stringhe di caratteri non destinate alla memorizzazione di soli testi conforme all'UCS). Questa API binaria è supportata su tutti i sistemi in cui è stato portato Java, anche quelli il cui sistema operativo non offre un'API di testo Unicode (il supporto può essere effettuato nell'applicazione nativa host o utilizzando le librerie standard fornite con la JVM o altri nativi indipendenti biblioteche.