À la découverte d'Unicode/Codage
Si chaque caractère peut être représenté à travers les points de code définis par le répertoire Unicode, l'informatique nécessite de leur attribuer en plus d'un numéro, une représentation binaire.
Si l'on pourrait s'attendre à ce qu'Unicode définisse un multiplet suffisamment large pour représenter chacun des points de code Unicode, pour des raisons historiques, la réalité est toute autre.
En pratique, il est souvent nécessaire de représenter ces points de code dans des unités définies préalablement à une époque où l'on pensait que huit ou seize bits seraient largement suffisants.
Pour être traités informatiquement, les points de code (qui définissent des caractères) doivent être représentables par une séquence de bits et/ou d'octets. Ceci est rendu possible au travers des systèmes de codage de caractères attribuant à chaque point de code une séquence d'unités de code.
En dehors de la Chine populaire, les codages de caractères les plus utilisés sont sans doute l'UTF-8 et l'UTF-16, dont nous donnons quelques notions ci-après.
Les autres codages existant sont les suivants : UTF-7; UTF-8; CESU-8; UCS-2; UTF-16; UTF-32 (UCS-4); UTF-EBCDIC; SCSU; Punycode; GB 18030;
UTF-8
modifierLe répertoire Unicode peut contenir plus d'un million de caractères, ce qui est bien trop grand pour être codé par un seul octet (limité à des valeurs entre 0 et 255). Techniquement, il s'agit de coder les caractères Unicode sous forme de séquences de un à quatre codet de un octet chacun.
Par exemple le caractère "€" (euro) est le 8365e caractère du répertoire Unicode, son index, ou point de code est donc 8364 (on commence à compter à partir de 0).
La principale caractéristique d'UTF-8 est qu'elle est rétro-compatible avec la norme ASCII 7 bits, c'est-à-dire que tout caractère ASCII se code en UTF-8 sous forme d'un unique octet, identique au code ASCII. Par exemple "A" (A majuscule) a pour code ASCII 65 et se code en UTF-8 par l'octet 65. Cela ne s'applique qu'aux textes en anglais, car toutes les autres langues utilisent des lettres avec diacritiques, ou carrément un autre alphabet que latin. Chaque caractère dont le point de code est supérieur à 127 (caractère non ASCII) se code sur 2 à 4 octets. Le caractère "€" (euro) se code par exemple sur 3 octets : 226, 130, et 172.
Codage UTF-8
modifierLe principe du codage UTF-8 est d'indiquer le nombre d'octets employés pour coder le caractère par une séquence de bits à 1 dans la partie des bits de poids fort du premier octet. La fin de la séquence de bits à 1 est marquée par un bit à 0. Les bits restant servent à coder les bits de poids fort du point de code du caractère.
- Un bit de poids fort à 0 indique un codage sur un octet, pour les caractères ASCII de 0 à 127 codés sur les 7 bits restant.
- Sinon, le nombre de bits à 1 indique le nombre total d'octets pour le caractère.
- La séquence à un bit à 1 est réservée pour les octets supplémentaires de codage par groupe de 6 bits. Cela permet de repérer une position (adresse mémoire ou flux de lecture) située au milieu du codage d'un caractère.
Le tableau ci-dessous résume le codage UTF-8, où les lettres représentent les bits du point de code du caractère encodé.
Séquence de bits | Points de code des caractères |
---|---|
0aaaaaaa
|
U+000000-U+00007F |
110aaaaa 10bbbbbb
|
U+000080-U+0007FF |
1110aaaa 10bbbbbb 10cccccc
|
U+000800-U+00FFFF |
11110aaa 10bbbbbb 10cccccc 10dddddd
|
U+010000-U+10FFFF |
Exemples
modifierType | Caractère | Point de code (hexadécimal) |
Valeur scalaire | Codage UTF-8 | ||
---|---|---|---|---|---|---|
décimal | binaire | binaire | hexadécimal | |||
Contrôles | [NUL]
|
U+0000 |
0 | 0000000
|
00000000 |
00
|
[US]
|
U+001F |
31 | 0011111
|
00011111 |
1F
| |
Texte | [SP]
|
U+0020 |
32 | 0100000
|
00100000 |
20
|
A | U+0041 |
65 | 1000001
|
01000001 |
41
| |
~ | U+007E |
126 | 1111110
|
01111110 |
7E
| |
Contrôles | [DEL]
|
U+007F |
127 | 1111111
|
01111111 |
7F
|
Texte | [NBSP]
|
U+00A0 |
160 | 00010 100000
|
11000010 10100000 |
C2 A0
|
é | U+00E9 |
233 | 00011 101001
|
11000011 10101001 |
C3 A9
| |
߿ | U+07FF |
2047 | 11111 111111
|
11011111 10111111 |
DF BF
| |
ࠀ | U+0800 |
2048 | 0000 100000 000000
|
11100000 10100000 10000000 |
E0 A0 80
| |
€ | U+20AC |
8 364 | 0010 000010 101100
|
11100010 10000010 10101100 |
E2 82 AC
| |
| U+D7FF |
55 295 | 1101 011111 111111
|
11101101 10011111 10111111 |
ED 9F BF
| |
Demi-codets | U+D800 |
(néant) | (codage interdit) | |||
U+DFFF
| ||||||
Usage privé | [] | U+E000 |
57 344 | 1110 000000 000000
|
11101110 10000000 10000000 |
EE 80 80
|
[] | U+F8FF |
63 743 | 1111 100011 111111
|
11101111 10100011 10111111 |
EF A3 BF
| |
Texte | 豈 | U+F900 |
63 744 | 1111 100100 000000
|
11101111 10100100 10000000 |
EF A4 80
|
﷏ | U+FDCF |
64 975 | 1111 110111 001111
|
11101111 10110111 10001111 |
EF B7 8F
| |
Non-caractères | U+FDD0 |
64 976 | 1111 110111 010000
|
11101111 10110111 10010000 |
EF B7 90
| |
U+FDEF |
65 007 | 1111 110111 101111
|
11101111 10110111 10101111 |
EF B7 AF
|
Variante : UTF-8 modifié
modifierLa variante « UTF-8 modifié » est un codage utilisé par Java basé sur UTF-8, mais codant les caractères au-delà de U+0x00FFFF sur 6 octets, c'est-à-dire 2 fois 3 octets pour les surrogates, car en Java le type caractère occupe 16 bits.
Séquence de bits | Points de code des caractères |
---|---|
0aaaaaaa
|
U+0000-U+007F |
110aaaaa 10bbbbbb
|
U+0080-U+07FF |
1110aaaa 10bbbbbb 10cccccc
|
U+0800-U+FFFF (incluant les paires U+D800-U+DBFF et U+DC00-U+DFFF) |
De plus, le caractère nul (U+0000) est codé sur deux octets (C0 80
), afin d'éviter l'octet nul, et de faciliter le repérage de fin de chaîne de caractère dans le code natif.
Variante : CESU-8
modifierLa variante CESU-8 est identique au « UTF-8 modifié » utilisé par Java, excepté le codage du caractère nul (U+0000).
UTF-16
modifierUTF-16 est un codage Unicode où chaque caractère est codé sur une suite de un ou deux mots de 16 bits.
L'UTF-16 fait maintenant partie intégrante de la norme Unicode, qui dans son chapitre 3 Conformance la définit de façon très stricte.
L'UTF-16 n'est pas l'UCS-2 qui est le codage, plus simple, de chaque caractère sur deux octets. Ces deux normes sont pourtant appelées toutes les deux Unicode, car le codage est le même tant que l'on n'utilise pas les plages U+D800 à U+DFFF (en principe réservées) et les plages après U+FFFF (peu utilisées en occident).
L'UTF-16 est en particulier utilisé dans les environnements windows. Dans ce système, les API dites unicode utilisent ce standard. Il en va de même du système NTFS.
UTF-16 est le standard de chaînes de caractères utilisé par l'UEFI[1].
Description
modifierLes points de code qui peuvent être représentés doivent être dans l’intervalle de validité U+0000 à U+10FFFF, et ne doivent pas être affectés à un non-caractère. Tous les caractères possibles dans Unicode possèdent de tels points de codes.
Tout point de code qui n’est pas un non-caractère, et dont la valeur peut être codée sur un seul codet de deux octets (16 bits), c’est-à-dire tout point de code U+0000 à U+D7FF et U+E000 à U+FFFD, est stocké sur un seul mot de 16 bits (la plage de non-caractères U+D800 à U+DFFF est donc exclue, c'est-à-dire les points de code dont les 5 bits de poids fort sont 11011
).
Dans les autres cas, le caractère est un point de code d’un plan supplémentaire (donc entre U+10000 et U+10FFFD et dont les 16 bits de poids faible ne doivent pas égaler 0xFFFE ou 0xFFFF) ; il est alors stocké sur 2 mots (codets) successifs de 16 bits chacun, dont les valeurs correspondent aux points de codes réservés dans les demi-zones d’indirection allouées dans le plan multilingue de base des normes Unicode et ISO/CEI 10646 :
- le premier mot aura les 6 bits de poids fort égaux à
110110
et sera donc compris dans l’intervalle [0xD800 .. 0xDBFF] (ici en numération hexadécimale) ; ce mot contiendra dans ses 10 bits de poids faible les 10 bits de poids fort de la différence (représentée sur 20 bits) entre le point de code à stocker et le premier point de code supplémentaire U+10000 ; - le second mot aura les 6 bits de poids fort égaux à
110111
et sera donc compris dans l’intervalle [0xDC00 .. 0xDFFF] (ici en numération hexadécimale) ; ce mot contiendra dans ses 10 bits de poids faible les 10 bits de poids faible du point de code à stocker.
Puis suivant le format de stockage des mots de 16 bits dans un flux ordonné d’octets, deux systèmes sont possibles pour le codage final :
Numéro du caractère | 00000000 000uuuuu xxxxxxyy yyyyyyyy
| |||
---|---|---|---|---|
Codage UTF-16BE (sur 2 octets) |
xxxxxxyy
|
yyyyyyyy
| ||
(seulement si uuuuu = 00000 )
| ||||
Codage UTF-16BE (sur 4 octets) |
110110ww
|
wwxxxxxx
|
110111yy
|
yyyyyyyy
|
avec wwww = uuuuu - 1 (si uuuuu > 00000 )
|
Numéro du caractère | 00000000 000uuuuu xxxxxxyy yyyyyyyy
| |||
---|---|---|---|---|
Codage UTF-16LE (sur 2 octets) |
yyyyyyyy
|
xxxxxxyy
| ||
(seulement si uuuuu = 00000 )
| ||||
Codage UTF-16LE (sur 4 octets) |
wwxxxxxx
|
110110ww
|
yyyyyyyy
|
110111yy
|
avec wwww = uuuuu - 1 (si uuuuu > 00000 )
|
L’indication du type de codage utilisé (ordre des octets) peut être implicite pour le protocole utilisé, ou précisé explicitement par ce protocole (en indiquant par exemple les noms réservés "UTF-16BE" ou "UTF-16LE" dans un entête de charset MIME). Si le protocole ne permet pas de spécifier l’ordre des octets, et s’il permet l’une ou l’autre des alternatives, on pourra utiliser le codage UTF-16 du point de code valide U+FEFF comme indicateur en tête du flux de données (car un changement d’ordre de ses octets à la lecture du flux conduira à un point de code U+FFFE, valide dans Unicode mais affecté à un non-caractère et donc interdit dans ce cas dans tout flux UTF-16. Ce point de code ainsi représenté (appelé marque d’ordonnancement des octets, byte order mark en anglais, abrégé BOM) ne sera codé qu’au début du flux de données, et permet de savoir comment a été codé le flux :
1er octet | 2ème octet | Codage effectif |
---|---|---|
0xFE |
0xFF |
big endian |
0xFF |
0xFE |
little endian |
Si l’une des deux séquences de deux octets chacune est présente en tête de flux, le type de codage en est déduit et la séquence est retirée du flux : elle ne représente aucun caractère du texte stocké dans ce flux de données. Si aucune des deux séquences ne figure en tête du flux de données, la norme Unicode spécifie que le flux doit être décodé en big endian (UTF-16BE).
Le BOM peut également être présent en UTF-8 pour indiquer explicitement le codage.