UTF-8 - UTF-8

UTF-8
Standard Standard Unicode
Classificazione Formato di trasformazione Unicode , ASCII esteso , codifica a larghezza variabile
si estende US-ASCII
Trasforma / Codifica ISO 10646 ( Unicode )
Preceduto da UTF-1

UTF-8 è una codifica di caratteri a larghezza variabile utilizzata per la comunicazione elettronica. Definito dallo standard Unicode, il nome deriva da Unicode (o Universal Coded Character Set ) Transformation Format – 8-bit .

UTF-8 è in grado di codificare tutti i 1.112.064 punti di codice di caratteri validi in Unicode utilizzando da una a quattro unità di codice da un byte (8 bit). I punti di codice con valori numerici inferiori, che tendono a verificarsi più frequentemente, vengono codificati utilizzando meno byte. È stato progettato per la retrocompatibilità con ASCII : i primi 128 caratteri di Unicode, che corrispondono uno a uno con ASCII, sono codificati utilizzando un singolo byte con lo stesso valore binario di ASCII, in modo che il testo ASCII valido sia valido UTF-8 codificato anche Unicode. Poiché i byte ASCII non si verificano quando si codificano punti di codice non ASCII in UTF-8, UTF-8 è sicuro da usare nella maggior parte dei linguaggi di programmazione e documenti che interpretano determinati caratteri ASCII in un modo speciale, come/( slash ) nei nomi dei file, \( backslash ) nelle sequenze di escape e %in printf .

UTF-8 è stato progettato come un'alternativa superiore a UTF-1 , una codifica a larghezza variabile proposta con compatibilità ASCII parziale che mancava di alcune funzionalità tra cui l' auto-sincronizzazione e la gestione completamente compatibile con ASCII di caratteri come le barre. Ken Thompson e Rob Pike hanno prodotto la prima implementazione per il sistema operativo Plan 9 nel settembre 1992. Ciò ha portato alla sua adozione da parte di X/Open come specifica per FSS-UTF , che sarebbe stata presentata ufficialmente per la prima volta all'USENIX nel gennaio 1993 e successivamente adottata dalla Internet Engineering Task Force (IETF) in RFC 2277 ( BCP 18 ) per il futuro lavoro degli standard Internet, sostituendo i set di caratteri a byte singolo come Latin-1 nelle RFC precedenti.

UTF-8 è di gran lunga la codifica più comune per il World Wide Web , rappresentando oltre il 97% di tutte le pagine Web e fino al 100% per alcune lingue, a partire dal 2021.

denominazione

Il codice IANA ( Internet Assigned Numbers Authority ) ufficiale per la codifica è "UTF-8". Tutte le lettere sono maiuscole e il nome è sillabato. Questa ortografia è utilizzata in tutti i documenti del Consorzio Unicode relativi alla codifica.

In alternativa, il nome " utf-8 " può essere utilizzato da tutti gli standard conformi all'elenco IANA (che includono intestazioni CSS , HTML , XML e HTTP ), poiché la dichiarazione non fa distinzione tra maiuscole e minuscole.

Altre varianti, come quelle che omettono il trattino o lo sostituiscono con uno spazio, ad esempio " utf8 " o " UTF 8 ", non sono accettate come corrette dalle norme vigenti. Nonostante ciò, la maggior parte dei browser Web è in grado di comprenderli, quindi gli standard destinati a descrivere la pratica esistente (come HTML5) possono effettivamente richiedere il loro riconoscimento.

Ufficiosamente, UTF-8-BOM e UTF-8-NOBOM vengono talvolta utilizzati per file di testo che contengono o non contengono rispettivamente un byte order mark (BOM). Soprattutto in Giappone, la codifica UTF-8 senza BOM è talvolta chiamata " UTF-8N ".

Windows XP e versioni successive, incluse tutte le versioni di Windows supportate, hanno la codepage 65001 , come sinonimo di UTF-8 (poiché il supporto di Windows 7 per UTF-8 è migliore) e Microsoft ha uno script per Windows 10 , per abilitarlo per impostazione predefinita per il suo programma Microsoft Notepad .

In PCL , UTF-8 è chiamato Symbol-ID "18N" (PCL supporta 183 codifiche di caratteri, chiamate Set di simboli, che potenzialmente potrebbero essere ridotte a uno, 18N, cioè UTF-8).

Codifica

Dalla restrizione dello spazio di codice Unicode a valori a 21 bit nel 2003, UTF-8 è definito per codificare i punti di codice da uno a quattro byte, a seconda del numero di bit significativi nel valore numerico del punto di codice. La tabella seguente mostra la struttura della codifica. I caratteri x vengono sostituiti dai bit del punto di codice.

Punto di codice <-> Conversione UTF-8
Primo punto di codice Ultimo punto di codice Byte 1 Byte 2 Byte 3 Byte 4
U+0000 U+007F 0xxxxxxx
U+0080 U+07FF 110xxxxx 10xxxxxx
U+0800 U+FFFF 1110xxxx 10xxxxxx 10xxxxxx
U+10000 U+10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

I primi 128 caratteri (US-ASCII) richiedono un byte. I successivi 1.920 caratteri necessitano di due byte per la codifica, che copre il resto di quasi tutti gli alfabeti latini , e anche le estensioni IPA , greco , cirillico , copto , armeno , ebraico , arabo , siriaco , thaana e alfabeti N'Ko , nonché come Combinazione di segni diacritici . Sono necessari tre byte per i caratteri nel resto del piano multilingue di base , che contiene praticamente tutti i caratteri di uso comune, inclusa la maggior parte dei caratteri cinesi, giapponesi e coreani . Sono necessari quattro byte per i caratteri negli altri piani di Unicode , che includono caratteri CJK meno comuni , vari script storici, simboli matematici ed emoji (simboli pittografici).

Un "carattere" può effettivamente richiedere più di 4 byte, ad esempio un carattere flag emoji richiede 8 byte poiché è "costruito da una coppia di valori scalari Unicode".

Esempi

Si consideri la codifica del simbolo dell'Euro , €:

  1. Il punto di codice Unicode per "€" è U+20AC.
  2. Poiché questo punto di codice si trova tra U+0800 e U+FFFF, la codifica richiederà tre byte.
  3. Esadecimale 20AC è binario 0010 0000 10 10 1100 . I due zeri iniziali vengono aggiunti perché una codifica a tre byte richiede esattamente sedici bit dal punto di codice.
  4. Poiché la codifica sarà lunga tre byte, il suo byte iniziale inizia con tre 1, quindi uno 0 ( 1110... )
  5. I quattro bit più significativi del punto di codice sono memorizzati nei restanti quattro bit di ordine inferiore di questo byte ( 1110 0010 ), lasciando 12 bit del punto di codice ancora da codificare ( ... 0000 10 10 1100 ).
  6. Tutti i byte di continuazione contengono esattamente sei bit dal punto di codice. Quindi i successivi sei bit del punto di codice sono memorizzati nei sei bit di ordine inferiore del byte successivo e 10 è memorizzato nei due bit di ordine elevato per contrassegnarlo come un byte di continuazione (quindi 10 000010 ).
  7. Infine, gli ultimi sei bit del punto di codice sono memorizzati nei sei bit di ordine inferiore del byte finale, e di nuovo 10 è memorizzato nei due bit di ordine elevato ( 10 101100 ).

I tre byte 1110 0010 10 000010 10 101100 possono essere scritti in modo più conciso in esadecimale , come E2 82 AC .

La tabella seguente riassume questa conversione, così come altre con lunghezze diverse in UTF-8. I colori indicano come i bit dal punto di codice sono distribuiti tra i byte UTF-8. Ulteriori bit aggiunti dal processo di codifica UTF-8 sono mostrati in nero.

Esempi di codifica UTF-8
Carattere Punto codice binario Binario UTF-8 Esadecimale UTF-8
$ U+0024 010 0100 0 0100100 24
? U+00A2 000 10 10 0010 110 00010 10 100010 C2 LA2
? U+0939 0000 1001 00 11 1001 1110 0000 10 100100 10 111001 MI0 LA4 SI9
U+20AC 0010 0000 10 10 1100 1110 0010 10 000010 10 101100 E2 82 AC
? U+D55C 1101 0101 01 01 1100 1110 1101 10 010101 10 011100 DE 95 9C
? U+10348 0 00 01 0000 0011 01 00 1000 11110 000 10 010000 10 001101 10 001000 F0 90 8D 88

ottale

L'uso da parte di UTF-8 di sei bit per byte per rappresentare i caratteri effettivi che vengono codificati, significa che la notazione ottale (che utilizza gruppi a 3 bit) può aiutare nel confronto tra le sequenze UTF-8 e nella conversione manuale.

Punto di codice ottale <-> Conversione ottale UTF-8
Primo punto di codice Ultimo punto di codice Punto di codice Byte 1 Byte 2 Byte 3 Byte 4
000 177 xxx xxx
0200 3777 xyy 3xx 2yy
04000 77777 xyyzz 34x 2yy 2zz
100000 177777 1xyyzz 35x 2yy 2zz
0200000 4177777 xyyzzww 36x 2yy 2zz 2ww

Con la notazione ottale, le cifre ottali arbitrarie, contrassegnate con x, y, z o w nella tabella, rimarranno invariate durante la conversione in o da UTF-8.

Esempio: Á = U+00C1 = 0301 (in ottale) è codificato come 303 201 in UTF-8 (C3 81 in esadecimale).
Esempio: € = U+20AC = 20254 è codificato come 342 202 254 in UTF-8 (E2 82 AC in esadecimale).

Layout della tabella codici

La tabella seguente riepiloga l'utilizzo delle unità di codice UTF-8 (singoli byte o ottetti ) in un formato di tabella codici . La metà superiore (da 0_ a 7_ ) è per i byte utilizzati solo nei codici a byte singolo, quindi sembra una normale tabella codici; la metà inferiore è per i byte di continuazione (da 8_ a B_ ) e per i byte iniziali (da C_ a F_ ), ed è spiegata ulteriormente nella legenda sottostante.

UTF-8
_0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _UN _B _C _D _E _F
(1 byte)
0_
NUL
0000
SOH
0001
STX
0002
ETX
0003
EOT
0004
ENQ
0005
ACK
0006
BEL
0007
BS
0008
HT
0009
LF
000A
VT
000B
FF
000C
CR
000D
SO
000E
SI
000F
(1)
1_
DLE
0010
DC1
0011
DC2
0012
DC3
0013
DC4
0014
NAK
0015
SIN
0016
ETB
0017
PU
0018
EM
0019
SUB
001A
ESC
001B
FS
001C
GS
001D
RS
001E
US
001F
(1)
2_
SP
0020
!
0021
"
0022
#
0023
$
0024
%
0025
&
0026
'
0027
(
0028
)
0029
*
002A
+
002B
,
002C
-
002D
.
002E
/
002F
(1)
3_
0
0030
1
0031
2
0032
3
0033
4
0034
5
0035
6
0036
7
0037
8
0038
9
0039
:
003A
;
003B
<
003C
=
003D
>
003E
?
003F
(1)
4_
@
0040
A
0041
B
0042
C
0043
D
0044
E
0045
F
0046
G
0047
H
0048
io
0049
J
004A
K
004B
L
004C
M
004D
N
004E
O
004F
(1)
5_
P
0050
Q
0051
R
0052
S
0053
T
0054
U
0055
V
0056
W
0057
X
0058
Y
0059
Z
005A
[
005B
\
005C
]
005D
^
005E
_
005F
(1)
6_
`
0060
uno
0061
b
0062
c
0063
d
0064
e
0065
f
0066
g
0067
ore
0068
io
0069
j
006A
k
006B
l
006C
m
006D
n
006E
o
006F
(1)
7_
p
0070
q
0071
r
0072
s
0073
t
0074
tu
0075
v
0076
w
0077
x
0078
e
0079
z
007A
{
007B
|
007C
}
007D
~
007E
DEL
007F

8_

+00

+01

+02

+03

+04

+05

+06

+07

+08

+09

+0A

+0B

+0C

+0D

+0 MI

+0F

9_

+10

+11

+12

+13

+14

+15

+16

+17

+18

+19

+1A

+1B

+1C

+1D

+1 Mi

+1F

UN_

+20

+21

+22

+23

+24

+25

+26

+27

+28

+29

+2A

+2B

+2C

+2D

+2 Mi

+2F

B_

+30

+31

+32

+33

+34

+35

+36

+37

+38

+39

+3A

+3B

+3C

+3D

+3E

+3FA
(2)
C_
2
0000
2
0040
latino
0080
latino
00C0
latino
0100
latino
0140
latino
0180
latino
01C0
latino
0200
IPA
0240
IPA
0280
IPA
02C0
accenti
0300
accenti
0340
greco
0380
Greco
03C0
(2)
D_
Cirillo
0400
Cirillo
0440
Cirillo
0480
Cirillo
04C0
Cirillo
0500
Armeni
0540
Ebraico
0580
Ebraico
05C0
arabo
0600
arabo
0640
arabo
0680
Arabo
06C0
siriaco
0700
arabo
0740
Thaana
0780
NKo
07C0
(3)
E_
Indica
0800
Varie
1000
Simbolo
2000
Kana
3000
CJK
4000
CJK
5000
CJK
6000
CJK
7000
CJK
8000
CJK
9000
asiatico
A000
Hangul
B000
Hangul
C000
Hangul
D000
PUA
E000
PUA
F000
(4)
F_
SMP…
10000
񀀀
40000
򀀀
80000
SSP…
C0000
SPUA-B
100000
4
140000
4
180000
4
1C0000
5
200000
5
1000000
5
2000000
5
3000000
6
4000000
6
4000000

  Le celle blu sono sequenze a 7 bit (a byte singolo). Non devono essere seguiti da un byte di continuazione.

  Le celle arancioni con un punto grande sono un byte di continuazione. Il numero esadecimale mostrato dopo il simbolo + è il valore dei 6 bit che aggiungono. Questo carattere non si verifica mai come primo byte di una sequenza a più byte.

  Le celle bianche sono i byte iniziali per una sequenza di più byte, la lunghezza mostrata sul bordo sinistro della riga. Il testo mostra i blocchi Unicode codificati da sequenze che iniziano con questo byte e il punto di codice esadecimale mostrato nella cella è il valore di carattere più basso codificato utilizzando quel byte iniziale.

  I globuli rossi non devono mai apparire in una sequenza UTF-8 valida. I primi due globuli rossi ( C0 e C1 ) potrebbero essere utilizzati solo per una codifica a 2 byte di un carattere ASCII a 7 bit che dovrebbe essere codificato in 1 byte; come descritto di seguito, tali sequenze "troppo lunghe" non sono consentite. Per capire perché questo è, considera il carattere 128, esadecimale 80 , binario 1000 0000 . Per codificarlo come 2 caratteri, i sei bit inferiori vengono memorizzati nel secondo carattere come 128 stesso 10 000000 , ma i due bit superiori vengono memorizzati nel primo carattere come 110 00010 , rendendo il primo carattere minimo C2. I globuli rossi nella riga F_ (da F5 a FD ) indicano byte iniziali di sequenze di 4 byte o più lunghe che non possono essere valide perché codificherebbero punti di codice maggiori del limite U+10FFFF di Unicode (un limite derivato dal punto di codice massimo codificabile in UTF-16 ). FE e FF non corrispondono a nessun modello di carattere consentito e pertanto non sono byte iniziali validi.

  Le celle rosa sono i byte iniziali per una sequenza di più byte, di cui sono valide alcune, ma non tutte, le possibili sequenze di continuazione. E0 e F0 potrebbero iniziare codifiche troppo lunghe, in questo caso viene mostrato il punto di codice non troppo lungo codificato più basso. F4 può avviare punti di codice maggiori di U+10FFFF che non sono validi. ED può avviare la codifica di un code point nel range U+D800–U+DFFF; questi non sono validi poiché sono riservati per metà surrogate UTF-16 .

Codifiche troppo lunghe

In linea di principio, sarebbe possibile aumentare il numero di byte in una codifica riempiendo il punto di codice con gli 0 iniziali. Per codificare il simbolo dell'euro € dall'esempio precedente in quattro byte anziché tre, potrebbe essere riempito con 0 iniziali fino a raggiungere una lunghezza di 21 bit – 000 000010 000010 101100 e codificato come 11110 000 10 000010 10 000010 10 101100 (o F0 82 82 AC in esadecimale). Questa è chiamata codifica troppo lunga .

Lo standard specifica che la codifica corretta di un punto di codice utilizza solo il numero minimo di byte necessari per contenere i bit significativi del punto di codice. Le codifiche più lunghe sono chiamate overlong e non sono rappresentazioni UTF-8 valide del punto di codice. Questa regola mantiene una corrispondenza uno a uno tra i punti di codice e le loro codifiche valide, in modo che vi sia una codifica valida univoca per ogni punto di codice. Ciò garantisce che i confronti e le ricerche di stringhe siano ben definiti.

Sequenze non valide e gestione degli errori

Non tutte le sequenze di byte sono valide UTF-8. Un decoder UTF-8 dovrebbe essere preparato per:

  • byte non validi
  • un byte di continuazione inaspettato
  • un byte non di continuazione prima della fine del carattere
  • la stringa che termina prima della fine del carattere (cosa che può accadere nel semplice troncamento di una stringa)
  • una codifica troppo lunga
  • una sequenza che decodifica in un punto di codice non valido

Molti dei primi decodificatori UTF-8 li decodificherebbero, ignorando i bit errati e accettando risultati troppo lunghi. UTF-8 non valido accuratamente predisposto potrebbe farli saltare o creare caratteri ASCII come NUL, barra o virgolette. UTF-8 non valido è stato utilizzato per aggirare le convalide di sicurezza in prodotti di alto profilo, tra cui il server Web IIS di Microsoft e il contenitore servlet Tomcat di Apache. RFC 3629 afferma "Le implementazioni dell'algoritmo di decodifica DEVONO proteggere dalla decodifica di sequenze non valide". Lo standard Unicode richiede ai decodificatori di "...trattare qualsiasi sequenza di unità di codice non valida come una condizione di errore. Ciò garantisce che non interpreterà né emetterà una sequenza di unità di codice non valida".

Dalla RFC 3629 (novembre 2003), le metà surrogate alta e bassa utilizzate da UTF-16 (da U+D800 a U+DFFF) e i punti di codice non codificabili da UTF-16 (quelli dopo U+10FFFF) non sono valori Unicode legali, e la loro codifica UTF-8 deve essere trattata come una sequenza di byte non valida. La mancata decodifica delle metà dei surrogati non accoppiate rende impossibile memorizzare UTF-16 non validi (come nomi di file di Windows o UTF-16 che sono stati suddivisi tra i surrogati) come UTF-8, mentre è possibile con WTF-8 .

Alcune implementazioni di decodificatori generano eccezioni sugli errori. Questo ha lo svantaggio che può trasformare quelli che altrimenti sarebbero errori innocui (come un errore "nessun file di questo tipo") in un denial of service . Ad esempio, le prime versioni di Python 3.0 uscivano immediatamente se la riga di comando o le variabili di ambiente contenevano UTF-8 non valido. Una pratica alternativa consiste nel sostituire gli errori con un carattere sostitutivo. Da Unicode 6 (ottobre 2010), lo standard (capitolo 3) ha raccomandato una "procedura consigliata" in cui l'errore termina non appena viene rilevato un byte non consentito. In questi decoder E1,A0,C0 sono due errori (2 byte nel primo). Ciò significa che un errore non è più lungo di tre byte e non contiene mai l'inizio di un carattere valido, e ci sono 21.952 diversi errori possibili. Lo standard consiglia inoltre di sostituire ogni errore con il carattere sostitutivo " " (U+FFFD).

Contrassegno dell'ordine dei byte

Se il carattere UTF-16 Unicode byte order mark (BOM, U+FEFF) si trova all'inizio di un file UTF-8, i primi tre byte saranno 0xEF , 0xBB , 0xBF .

Lo standard Unicode non richiede né consiglia l'uso del BOM per UTF-8, ma avverte che potrebbe essere rilevato all'inizio di un file transcodificato da un'altra codifica. Sebbene il testo ASCII codificato utilizzando UTF-8 sia compatibile con le versioni precedenti con ASCII, ciò non è vero quando le raccomandazioni dello standard Unicode vengono ignorate e viene aggiunta una distinta base. Una BOM può confondere il software che non è preparato per questo, ma può accettare anche UTF-8, ad esempio linguaggi di programmazione che consentono byte non ASCII in stringhe letterali ma non all'inizio del file. Tuttavia, c'era e c'è ancora un software che inserisce sempre un BOM durante la scrittura di UTF-8 e si rifiuta di interpretare correttamente UTF-8 a meno che il primo carattere non sia un BOM (o il file contenga solo ASCII).

Alcuni linguaggi di programmazione e formati di file hanno il loro modo di contrassegnare l'utilizzo di codifiche come UTF-8 nel codice sorgente. Gli esempi includono HTML <meta charset="UTF-8"/> e Python 2.7 # coding: utf-8

Adozione

Utilizzo delle principali codifiche sul web dal 2001 al 2012 registrato da Google, con UTF-8 che ha superato tutte le altre nel 2008 e oltre il 60% del web nel 2012 (da allora avvicinandosi al 100%). La cifra ASCII- only include tutte le pagine web che contengono solo caratteri ASCII, indipendentemente dall'intestazione dichiarata.

UTF-8 è la raccomandazione del WHATWG per le specifiche HTML e DOM e Internet Mail Consortium consiglia che tutti i programmi di posta elettronica siano in grado di visualizzare e creare la posta utilizzando UTF-8. Il World Wide Web Consortium consiglia UTF-8 come codifica predefinita in XML e HTML (e non solo utilizzando UTF-8, indicandolo anche nei metadati), "anche quando tutti i caratteri sono nell'intervallo ASCII .. Utilizzando non-UTF- 8 codifiche possono avere risultati imprevisti". Molti altri standard supportano solo UTF-8, ad esempio lo scambio JSON aperto lo richiede.

UTF-8 è stata la codifica più comune per il World Wide Web dal 2008. A partire da ottobre 2021, UTF-8 rappresenta in media il 97,3% di tutte le pagine web; e 988 delle prime 1.000 pagine web con il punteggio più alto. UTF-8 include ASCII come sottoinsieme; quasi nessun sito web dichiara utilizzato solo ASCII. Diverse lingue utilizzano il 100,0% di UTF-8.

Per i file di testo locali, l'utilizzo di UTF-8 è inferiore e molte codifiche legacy a byte singolo (e CJK multibyte) rimangono in uso. La causa principale sono gli editor che non visualizzano o scrivono UTF-8 a meno che il primo carattere in un file non sia un byte order mark (BOM), rendendo impossibile per altri software utilizzare UTF-8 senza essere riscritto per ignorare il byte order mark in ingresso e aggiungilo in uscita. Recentemente c'è stato qualche miglioramento, Blocco note su Windows 10 scrive UTF-8 senza BOM per impostazione predefinita e alcuni file di sistema su Windows 11 richiedono UTF-8 e quasi tutti i file su macOS e Linux devono essere UTF-8 (senza un BOM). Java , con la sua API NIO, legge e scrive per impostazione predefinita i file UTF-8 e si sta muovendo per farlo per tutte le altre API di file. Funziona già per tutte le API sulla maggior parte delle piattaforme, ad eccezione di Windows . "La scelta di UTF-8 si applica solo alle API Java standard e non al linguaggio Java, che continuerà a utilizzare UTF-16". Molti altri linguaggi di programmazione sono impostati per impostazione predefinita su UTF-8 per l'I/O; o pianificare la migrazione a UTF-8, come Python che si sta preparando a "cambiare la codifica predefinita in UTF-8 [poiché è] diventata la codifica di testo standard di fatto". La maggior parte dei database supporta UTF-8 (a volte l'unica opzione come con alcuni formati di file), inclusi quelli di Microsoft da SQL Server 2019, con conseguente aumento della velocità del 35% e "riduzione di quasi il 50% dei requisiti di archiviazione".

Internamente l'utilizzo del software è inferiore, con UTF-16 o UCS-2 in uso, in particolare su Windows, ma anche da JavaScript , Python , Qt e molte altre librerie software multipiattaforma. La compatibilità con l' API di Windows è la ragione principale di ciò, sebbene anche la convinzione che l'indicizzazione diretta di BMP migliori la velocità fosse un fattore. Il software più recente ha iniziato a utilizzare UTF-8: la primitiva stringa predefinita utilizzata in Go , Julia , Rust , Swift 5 e PyPy è UTF-8, una versione futura di Python intende memorizzare le stringhe come UTF-8 e versioni moderne di Microsoft Visual Studio usa UTF-8 internamente (tuttavia richiedono ancora un'opzione della riga di comando per leggere o scrivere UTF-8). UTF-8 è "l'unica codifica di testo che deve essere supportata dallo standard C++", a partire da C++20 . A partire da maggio 2019, Microsoft ha invertito il suo corso supportando solo UTF-16 per l'API di Windows, fornendo la possibilità di impostare UTF-8 come "code page" per l'API multi-byte (in precedenza era impossibile), e ora Microsoft consiglia (ai programmatori) di usare UTF-8 per le app UWP ( Universal Windows Platform ), pur continuando a mantenere un'interfaccia "Unicode" legacy (che significa UTF-16).

Storia

L' Organizzazione internazionale per la standardizzazione (ISO) ha deciso di comporre un set di caratteri multibyte universale nel 1989. La bozza dello standard ISO 10646 conteneva un allegato non richiesto chiamato UTF-1 che forniva una codifica del flusso di byte dei suoi punti di codice a 32 bit . Questa codifica non era soddisfacente per motivi di prestazioni, tra gli altri problemi, e il problema più grande era probabilmente che non aveva una netta separazione tra ASCII e non ASCII: i nuovi strumenti UTF-1 sarebbero retrocompatibili con il testo codificato in ASCII, ma Il testo con codifica UTF-1 potrebbe confondere il codice esistente in attesa di ASCII (o ASCII esteso ), perché potrebbe contenere byte di continuazione nell'intervallo 0x21–0x7E che significava qualcos'altro in ASCII, ad esempio 0x2F per '/', il separatore di directory del percorso Unix , e questo esempio si riflette nel nome e nel testo introduttivo della sua sostituzione. La tabella che segue è stata ricavata da una descrizione testuale in allegato.

UTF-1
Numero
di byte
Primo
punto di codice
Ultimo
punto di codice
Byte 1 Byte 2 Byte 3 Byte 4 Byte 5
1 U+0000 U+009F 00–9F
2 U+00A0 U+00FF A0 LA0–FF
2 U+0100 U+4015 LA1–FA5 21–7E, LA0–FF
3 U+4016 U+38E2D F6-FB 21–7E, LA0–FF 21–7E, LA0–FF
5 U+38E2E U+7FFFFFFF FC–FF 21–7E, LA0–FF 21–7E, LA0–FF 21–7E, LA0–FF 21–7E, LA0–FF

Nel luglio 1992, il comitato X/Open XoJIG stava cercando una codifica migliore. Dave Prosser di Unix System Laboratories ha presentato una proposta per uno che avesse caratteristiche di implementazione più veloci e ha introdotto il miglioramento che i caratteri ASCII a 7 bit rappresenterebbero solo se stessi; tutte le sequenze multibyte includerebbero solo i byte in cui è stato impostato il bit più alto. Il nome File System Safe UCS Transformation Format (FSS-UTF) e la maggior parte del testo di questa proposta sono stati successivamente conservati nella specifica finale.

FSS-UTF

Proposta FSS-UTF (1992)
Numero
di byte
Primo
punto di codice
Ultimo
punto di codice
Byte 1 Byte 2 Byte 3 Byte 4 Byte 5
1 U+0000 U+007F 0xxxxxxx
2 U+0080 U+207F 10xxxxxx 1xxxxxxx
3 U+2080 U+8207F 110xxxxx 1xxxxxxx 1xxxxxxx
4 U+82080 U+208207F 1110xxxx 1xxxxxxx 1xxxxxxx 1xxxxxxx
5 U+2082080 U+7FFFFFFF 11110xxx 1xxxxxxx 1xxxxxxx 1xxxxxxx 1xxxxxxx

Nell'agosto 1992, questa proposta è stata fatta circolare da un rappresentante IBM X/Open alle parti interessate. Una modifica di Ken Thompson del gruppo del sistema operativo Plan 9 presso i Bell Labs lo ha reso un po' meno efficiente in termini di bit rispetto alla proposta precedente, ma in modo cruciale gli ha permesso di essere auto-sincronizzato , consentendo a un lettore di iniziare ovunque e rilevare immediatamente i limiti della sequenza di byte. Ha anche abbandonato l'uso dei bias e ha invece aggiunto la regola che è consentita solo la codifica più breve possibile; l'ulteriore perdita di compattezza è relativamente insignificante, ma i lettori ora devono cercare codifiche non valide per evitare problemi di affidabilità e soprattutto di sicurezza. Il disegno di Thompson è stato delineato il 2 settembre 1992, su una tovaglietta in una tavola calda del New Jersey con Rob Pike . Nei giorni seguenti, Pike e Thompson lo implementarono e aggiornarono Plan 9 per utilizzarlo per tutto il tempo, quindi comunicarono il loro successo a X/Open, che lo accettò come specifica per FSS-UTF.

FSS-UTF (1992) / UTF-8 (1993)
Numero
di byte
Primo
punto di codice
Ultimo
punto di codice
Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6
1 U+0000 U+007F 0xxxxxxx
2 U+0080 U+07FF 110xxxxx 10xxxxxx
3 U+0800 U+FFFF 1110xxxx 10xxxxxx 10xxxxxx
4 U+10000 U+1FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5 U+200000 U+3FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6 U+4000000 U+7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

UTF-8 è stato presentato ufficialmente per la prima volta alla conferenza USENIX a San Diego , dal 25 al 29 gennaio 1993. L' Internet Engineering Task Force ha adottato UTF-8 nella sua politica sui set di caratteri e le lingue in RFC 2277 ( BCP 18) per Internet futuro gli standard funzionano, sostituendo i set di caratteri a byte singolo come Latin-1 nelle RFC precedenti.

Nel novembre 2003, UTF-8 è stato limitato dalla RFC  3629 per corrispondere ai vincoli della codifica dei caratteri UTF-16 : il divieto esplicito di punti di codice corrispondenti ai caratteri surrogati alto e basso ha rimosso più del 3% delle sequenze a tre byte e termina a U+10FFFF ha rimosso più del 48% delle sequenze di quattro byte e tutte le sequenze di cinque e sei byte.

Standard

Esistono diverse definizioni correnti di UTF-8 in vari documenti standard:

  • RFC  3629 / STD 63 (2003), che stabilisce UTF-8 come elemento di protocollo Internet standard
  • RFC  5198 definisce UTF-8 NFC per Network Interchange (2008)
  • ISO/IEC 10646: 2014 § 9.1 (2014)
  • Lo standard Unicode, versione 11.0 (2018)

Sostituiscono le definizioni date nelle seguenti opere obsolete:

  • Lo standard Unicode, versione 2.0 , appendice A (1996)
  • ISO/IEC 10646-1: 1993 Emendamento 2 / Allegato R (1996)
  • RFC  2044 (1996)
  • RFC  2279 (1998)
  • Lo standard Unicode, versione 3.0 , §2.3 (2000) più la rettifica n. 1: UTF-8 Shortest Form (2000)
  • Allegato n. 27 dello standard Unicode: Unicode 3.1 (2001)
  • Lo standard Unicode, versione 5.0 (2006)
  • Lo standard Unicode, versione 6.0 (2010)

Sono tutti uguali nella loro meccanica generale, con le principali differenze su questioni come l'intervallo consentito di valori del punto di codice e la gestione sicura di input non validi.

Confronto con altre codifiche

Alcune delle caratteristiche importanti di questa codifica sono le seguenti:

  • Compatibilità con le versioni precedenti: la compatibilità con le versioni precedenti con ASCII e l'enorme quantità di software progettato per elaborare il testo codificato in ASCII è stata la principale forza trainante della progettazione di UTF-8. In UTF-8, i singoli byte con valori nell'intervallo da 0 a 127 vengono mappati direttamente ai punti di codice Unicode nell'intervallo ASCII. I singoli byte in questo intervallo rappresentano i caratteri, come in ASCII. Inoltre, i byte a 7 bit (byte in cui il bit più significativo è 0) non compaiono mai in una sequenza a più byte e nessuna sequenza a più byte valida viene decodificata in un punto di codice ASCII. Una sequenza di byte a 7 bit è sia ASCII valido che UTF-8 valido e in entrambe le interpretazioni rappresenta la stessa sequenza di caratteri. Pertanto, i byte a 7 bit in un flusso UTF-8 rappresentano tutti e solo i caratteri ASCII nel flusso. Pertanto, molti elaboratori di testo, parser, protocolli, formati di file, programmi di visualizzazione di testo, ecc., che utilizzano caratteri ASCII per scopi di formattazione e controllo, continueranno a funzionare come previsto trattando il flusso di byte UTF-8 come una sequenza di caratteri a byte, senza decodificare le sequenze multibyte. I caratteri ASCII su cui ruota l'elaborazione, come punteggiatura, spazi bianchi e caratteri di controllo non verranno mai codificati come sequenze multibyte. È quindi sicuro che tali processori semplicemente ignorino o passino attraverso le sequenze multi-byte, senza decodificarle. Ad esempio, gli spazi bianchi ASCII possono essere utilizzati per tokenizzare un flusso UTF-8 in parole; I line-feed ASCII possono essere usati per dividere un flusso UTF-8 in linee; e i caratteri ASCII NUL possono essere utilizzati per dividere i dati con codifica UTF-8 in stringhe con terminazione null. Allo stesso modo, molte stringhe di formato utilizzate dalle funzioni di libreria come "printf" gestiranno correttamente gli argomenti di input con codifica UTF-8.
  • Fallback e rilevamento automatico: solo un piccolo sottoinsieme di possibili stringhe di byte è una stringa UTF-8 valida: i byte da C0, C1 e da F5 a FF non possono essere visualizzati e i byte con il bit più alto devono essere in coppia e altri requisiti . È estremamente improbabile che un testo leggibile in qualsiasi ASCII esteso sia valido UTF-8. Parte della popolarità di UTF-8 è dovuta al fatto che fornisce una forma di retrocompatibilità anche per questi. Un processore UTF-8 che riceve erroneamente ASCII esteso come input può quindi "rilevarlo automaticamente" con un'affidabilità molto elevata. Gli errori di fallback saranno falsi negativi e questi saranno rari. Inoltre, in molte applicazioni, come la visualizzazione del testo, la conseguenza di un fallback errato è solitamente lieve. Un flusso UTF-8 può semplicemente contenere errori, con il risultato che lo schema di rilevamento automatico produce falsi positivi; ma il rilevamento automatico ha successo nella maggior parte dei casi, specialmente con testi più lunghi, ed è ampiamente utilizzato. Funziona anche per "ripiegare" o sostituire byte a 8 bit utilizzando il punto di codice appropriato per una codifica legacy solo quando vengono rilevati errori nell'UTF-8, consentendo il ripristino anche se UTF-8 e la codifica legacy sono concatenate nello stesso file.
  • Codice prefisso : il primo byte indica il numero di byte nella sequenza. La lettura da un flusso può decodificare istantaneamente ogni singola sequenza completamente ricevuta, senza dover prima attendere il primo byte di una sequenza successiva o un'indicazione di fine flusso. La lunghezza delle sequenze multi-byte è facilmente determinabile dagli esseri umani in quanto è semplicemente il numero di 1 di ordine superiore nel byte iniziale. Un carattere errato non verrà decodificato se uno stream termina a metà sequenza.
  • Auto-sincronizzazione : i byte iniziali e i byte di continuazione non condividono valori (i byte di continuazione iniziano con i bit 10 mentre i byte singoli iniziano con 0 e i byte più lunghi iniziano con 11 ). Ciò significa che una ricerca non troverà accidentalmente la sequenza per un carattere che inizia nel mezzo di un altro carattere. Significa anche che l'inizio di un carattere può essere trovato da una posizione casuale eseguendo il backup di un massimo di 3 byte per trovare il byte iniziale. Un carattere errato non verrà decodificato se uno stream inizia a metà sequenza e una sequenza più corta non apparirà mai all'interno di una più lunga.
  • Ordinamento: i valori scelti dei byte iniziali significano che un elenco di stringhe UTF-8 può essere ordinato in ordine di punti di codice ordinando le sequenze di byte corrispondenti.

Byte singolo

  • UTF-8 può codificare qualsiasi carattere Unicode , evitando la necessità di capire e impostare una " code page " o indicare in altro modo quale set di caratteri è in uso e consentendo l'output in più script contemporaneamente. Per molti script è stata utilizzata più di una codifica a byte singolo, quindi anche la conoscenza dello script non era sufficiente per visualizzarlo correttamente.
  • I byte 0xFE e 0xFF non vengono visualizzati, quindi un flusso UTF-8 valido non corrisponde mai al contrassegno dell'ordine dei byte UTF-16 e quindi non può essere confuso con esso. L'assenza di 0xFF (0377) elimina anche la necessità di sfuggire a questo byte in Telnet (e nella connessione di controllo FTP).
  • Il testo con codifica UTF-8 è più grande delle codifiche specializzate a byte singolo, ad eccezione dei caratteri ASCII semplici. Nel caso di script che utilizzavano set di caratteri a 8 bit con caratteri non latini codificati nella metà superiore (come la maggior parte delle code page dell'alfabeto cirillico e greco ), i caratteri in UTF-8 saranno il doppio della dimensione. Per alcuni script, come il tailandese e il devanagari (utilizzato da varie lingue dell'Asia meridionale), i caratteri triplicheranno di dimensioni. Ci sono anche esempi in cui un singolo byte si trasforma in un carattere composito in Unicode ed è quindi sei volte più grande in UTF-8. Ciò ha causato obiezioni in India e in altri paesi.
  • È possibile in UTF-8 (o qualsiasi altra codifica a lunghezza variabile) dividere o troncare una stringa nel mezzo di un carattere. Se i due pezzi non vengono riaggiunti successivamente prima dell'interpretazione come caratteri, ciò può introdurre una sequenza non valida sia alla fine della sezione precedente che all'inizio della successiva e alcuni decodificatori non conserveranno questi byte e provocheranno la perdita di dati. Poiché UTF-8 è auto-sincronizzato, questo non introdurrà mai un carattere valido diverso ed è anche abbastanza facile spostare il punto di troncamento all'indietro all'inizio di un carattere.
  • Se i punti di codice sono tutti della stessa dimensione, è facile misurare un numero fisso di essi. A causa della documentazione dell'era ASCII in cui "carattere" è usato come sinonimo di "byte", questo è spesso considerato importante. Tuttavia, misurando le posizioni delle stringhe utilizzando byte anziché "caratteri", la maggior parte degli algoritmi può essere adattata in modo semplice ed efficiente per UTF-8. La ricerca di una stringa all'interno di una stringa lunga può essere eseguita ad esempio byte per byte; la proprietà di autosincronizzazione previene i falsi positivi.

Altro multi-byte

  • UTF-8 può codificare qualsiasi carattere Unicode . I file in diversi script possono essere visualizzati correttamente senza dover scegliere la tabella codici o il carattere corretti. Ad esempio, cinese e arabo possono essere scritti nello stesso file senza markup specializzato o impostazioni manuali che specificano una codifica.
  • UTF-8 è auto-sincronizzato : i confini dei caratteri sono facilmente identificabili eseguendo la scansione di modelli di bit ben definiti in entrambe le direzioni. Se i byte vengono persi a causa di un errore o di un danneggiamento , è sempre possibile individuare il successivo carattere valido e riprendere l'elaborazione. Se è necessario accorciare una stringa per adattarla a un campo specificato, è possibile trovare facilmente il carattere valido precedente. Molte codifiche multibyte come Shift JIS sono molto più difficili da risincronizzare. Ciò significa anche che gli algoritmi di ricerca delle stringhe orientati ai byte possono essere utilizzati con UTF-8 (poiché un carattere è uguale a una "parola" composta da così tanti byte), le versioni ottimizzate delle ricerche di byte possono essere molto più veloci a causa dell'hardware supporto e tabelle di ricerca che hanno solo 256 voci. L'autosincronizzazione richiede tuttavia che i bit siano riservati per questi marcatori in ogni byte, aumentando la dimensione.
  • Efficiente per codificare utilizzando semplici operazioni bit per bit . UTF-8 non richiede operazioni matematiche più lente come moltiplicazioni o divisioni (a differenza di Shift JIS , GB 2312 e altre codifiche).
  • UTF-8 richiederà più spazio di una codifica multibyte progettata per uno script specifico. Le codifiche legacy dell'Asia orientale generalmente utilizzavano due byte per carattere ma richiedono tre byte per carattere in UTF-8.

UTF-16

  • Le codifiche di byte e UTF-8 sono rappresentate da array di byte nei programmi e spesso non è necessario eseguire alcuna operazione su una funzione durante la conversione del codice sorgente da una codifica di byte a UTF-8. UTF-16 è rappresentato da array di parole a 16 bit e la conversione in UTF-16 mantenendo la compatibilità con i programmi basati su ASCII esistenti (come è stato fatto con Windows) richiede ogni API e struttura dati che richiede la duplicazione di una stringa, una versione che accetta stringhe di byte e un'altra versione che accetta UTF-16. Se non è necessaria la compatibilità con le versioni precedenti, è comunque necessario modificare tutta la gestione delle stringhe.
  • Il testo codificato in UTF-8 sarà più piccolo dello stesso testo codificato in UTF-16 se sono presenti più punti di codice al di sotto di U+0080 rispetto all'intervallo U+0800..U+FFFF. Questo è vero per tutte le lingue europee moderne. È spesso vero anche per lingue come il cinese, a causa del gran numero di spazi, nuove righe, cifre e markup HTML nei file tipici.
  • La maggior parte delle comunicazioni (ad es. HTML e IP) e dell'archiviazione (ad es. per Unix) è stata progettata per un flusso di byte . Una stringa UTF-16 deve utilizzare una coppia di byte per ogni unità di codice:
    • L'ordine di questi due byte diventa un problema e deve essere specificato nel protocollo UTF-16, ad esempio con un byte order mark .
    • Se manca un numero dispari di byte da UTF-16, l'intero resto della stringa sarà testo senza significato. Eventuali byte mancanti da UTF-8 consentiranno comunque di recuperare il testo in modo accurato a partire dal carattere successivo dopo i byte mancanti.

Derivati

Le seguenti implementazioni mostrano lievi differenze rispetto alla specifica UTF-8. Sono incompatibili con la specifica UTF-8 e possono essere respinti dalle applicazioni UTF-8 conformi.

CESU-8

Unicode Technical Report #26 assegna il nome CESU-8 a una variante non standard di UTF-8, in cui i caratteri Unicode nei piani supplementari sono codificati utilizzando sei byte, anziché i quattro byte richiesti da UTF-8. La codifica CESU-8 tratta ciascuna metà di una coppia di surrogati UTF-16 a quattro byte come un carattere UCS-2 a due byte, producendo due caratteri UTF-8 a tre byte, che insieme rappresentano il carattere supplementare originale. I caratteri Unicode all'interno del piano multilingue di base vengono visualizzati come normalmente in UTF-8. Il rapporto è stato scritto per riconoscere e formalizzare l'esistenza di dati codificati come CESU-8, nonostante il Consorzio Unicode ne scoraggiasse l'uso, e rileva che una possibile ragione intenzionale per la codifica CESU-8 è la conservazione del confronto binario UTF-16.

La codifica CESU-8 può derivare dalla conversione di dati UTF-16 con caratteri supplementari in UTF-8, utilizzando metodi di conversione che presuppongono dati UCS-2, il che significa che non sono a conoscenza dei caratteri supplementari UTF-16 a quattro byte. È principalmente un problema sui sistemi operativi che utilizzano ampiamente UTF-16 internamente, come Microsoft Windows .

In Oracle Database , il UTF8set di caratteri utilizza la codifica CESU-8 ed è deprecato. Il AL32UTF8set di caratteri utilizza la codifica UTF-8 conforme agli standard ed è preferito.

CESU-8 è vietato per l'uso in documenti HTML5 .

MySQL utf8mb3

In MySQL , il utf8mb3set di caratteri è definito come dati codificati UTF-8 con un massimo di tre byte per carattere, il che significa che sono supportati solo i caratteri Unicode nel Basic Multilingual Plane (cioè da UCS-2 ). I caratteri Unicode nei piani supplementari non sono esplicitamente supportati. utf8mb3è deprecato a favore del utf8mb4set di caratteri, che utilizza la codifica UTF-8 conforme agli standard. utf8è un alias per utf8mb3, ma è destinato a diventare un alias per utf8mb4in una futura versione di MySQL. È possibile, sebbene non supportato, memorizzare i dati codificati CESU-8 in utf8mb3, gestendo i dati UTF-16 con caratteri supplementari come se fosse UCS-2.

UTF-8 . modificato

UTF-8 modificato (MUTF-8) ha avuto origine nel linguaggio di programmazione Java . In UTF-8 modificato, il carattere null (U+0000) utilizza la codifica overlong a due byte 110 00000 10 000000 ( C0 80 esadecimale ), invece di 00000000 ( 00 esadecimale ). Le stringhe UTF-8 modificate non contengono mai byte nulli effettivi, ma possono contenere tutti i punti di codice Unicode incluso U+0000, che consente l'elaborazione di tali stringhe (con un byte nullo aggiunto) dalle tradizionali funzioni di stringa con terminazione null . Tutte le implementazioni UTF-8 modificate note trattano anche le coppie di surrogati come in CESU-8 .

Nell'uso normale, il linguaggio supporta lo standard UTF-8 durante la lettura e la scrittura di stringhe tramite InputStreamReadere OutputStreamWriter(se è il set di caratteri predefinito della piattaforma o come richiesto dal programma). Tuttavia, utilizza UTF-8 modificato per la serializzazione di oggetti tra le altre applicazioni di DataInpute DataOutput, per Java Native Interface e per incorporare stringhe costanti nei file di classe .

Anche il formato dex definito da Dalvik utilizza lo stesso UTF-8 modificato per rappresentare i valori delle stringhe. Tcl utilizza anche lo stesso UTF-8 modificato di Java per la rappresentazione interna dei dati Unicode, ma utilizza il rigoroso CESU-8 per i dati esterni.

WTF-8

In WTF-8 (Wobbly Transformation Format, 8-bit ) sono consentite metà surrogate non accoppiate (da U+D800 a U+DFFF). Questo è necessario per memorizzare UTF-16 possibilmente non valido, come i nomi di file di Windows. Molti sistemi che si occupano di UTF-8 funzionano in questo modo senza considerarlo una codifica diversa, in quanto è più semplice.

(Il termine "WTF-8" è stato anche usato in modo umoristico per riferirsi a UTF-8 doppiamente codificato erroneamente a volte con l'implicazione che i byte CP1252 sono gli unici codificati.)

PEP 383

La versione 3 del linguaggio di programmazione Python tratta ogni byte di un flusso di byte UTF-8 non valido come un errore (vedi anche le modifiche con la nuova modalità UTF-8 in Python 3.7); questo dà 128 diversi possibili errori. Le estensioni sono state create per consentire a qualsiasi sequenza di byte che si presume sia UTF-8 di essere trasformata senza perdita in UTF-16 o UTF-32, traducendo i 128 possibili byte di errore in punti di codice riservati e trasformando quei punti di codice in errore byte per l'output UTF-8. L'approccio più comune è tradurre i codici in U+DC80...U+DCFF che sono valori surrogati bassi (finali) e quindi "non validi" UTF-16, come usato dal PEP 383 di Python (o "surrogateescape") approccio. Un'altra codifica chiamata MirBSD OPTU-8/16 li converte in U+EF80...U+EFFF in un'area ad uso privato . In entrambi gli approcci, il valore del byte è codificato negli otto bit bassi del punto di codice di uscita.

Queste codifiche sono molto utili perché evitano la necessità di gestire stringhe di byte "non valide" fino a molto tempo dopo, se non del tutto, e consentono agli array di byte "testo" e "dati" di essere lo stesso oggetto. Se un programma desidera utilizzare internamente UTF-16, questi sono necessari per preservare e utilizzare nomi di file che possono utilizzare UTF-8 non validi; poiché l'API del filesystem di Windows utilizza UTF-16, la necessità di supportare UTF-8 non valido è minore.

Affinché la codifica sia reversibile, le codifiche UTF-8 standard dei punti di codice utilizzati per i byte errati devono essere considerate non valide. Ciò rende la codifica incompatibile con WTF-8 o CESU-8 (sebbene solo per 128 punti di codice). Quando si ricodifica è necessario fare attenzione alle sequenze di punti del codice di errore che riconvertono in UTF-8 valido, che può essere utilizzato da software dannoso per ottenere caratteri imprevisti nell'output, sebbene ciò non possa produrre caratteri ASCII, quindi è considerato relativamente sicuro, poiché le sequenze dannose (come lo scripting tra siti ) di solito si basano su caratteri ASCII.

Guarda anche

Appunti

Riferimenti

link esterno