Il n'existe pas de caractère Unicode qui puisse être stocké dans un encodage mais pas dans un autre. C'est simplement parce que les caractères Unicode valides ont été limités à ce qui peut être stocké dans UTF-16 (qui a la plus petite capacité des trois encodages). En d'autres termes, l'UTF-8 et l'UTF-32 ne sont pas compatibles. pourrait peuvent être utilisés pour représenter une gamme plus large de caractères que l'UTF-16, mais ils ne sont pas . Lisez la suite pour plus de détails.
UTF-8
UTF-8 est un code à longueur variable. Certains caractères nécessitent un octet, d'autres deux, d'autres encore trois ou quatre. Les octets de chaque caractère sont simplement écrits les uns après les autres comme un flux continu d'octets.
Alors que certains caractères UTF-8 peuvent avoir une longueur de 4 octets, UTF-8 ne peut pas coder 2^32 caractères . C'est loin d'être le cas. Je vais essayer d'en expliquer les raisons.
Le logiciel qui lit un flux UTF-8 reçoit simplement une séquence d'octets - comment est-il censé décider si les 4 octets suivants sont un seul caractère de 4 octets, ou deux caractères de 2 octets, ou quatre caractères de 1 octet (ou une autre combinaison) ? En gros, cela se fait en décidant que certaines séquences de 1 octet ne sont pas des caractères valides, que certaines séquences de 2 octets ne sont pas des caractères valides, et ainsi de suite. Lorsque ces séquences non valides apparaissent, il est supposé qu'elles font partie d'un plus longtemps séquence.
Je suis sûr que vous avez déjà vu un autre exemple de ce phénomène : il s'agit de l'échappement. Dans de nombreux langages de programmation, il est décidé que le \
dans le code source d'une chaîne ne se traduit pas par un caractère valide dans la forme "compilée" de la chaîne. Lorsqu'un tel caractère est trouvé dans le code source, il est supposé faire partie d'une séquence plus longue, comme par exemple \n
o \xFF
. Notez que \x
est une séquence de 2 caractères non valide, et \xF
est une séquence de 3 caractères non valide, mais \xFF
est une séquence valide de 4 caractères.
Fondamentalement, il y a un compromis entre avoir beaucoup de caractères et avoir des caractères plus courts. Si vous voulez 2^32 caractères, ils doivent avoir une longueur moyenne de 4 octets. Si vous voulez que tous vos caractères soient de 2 octets ou moins, alors vous ne pouvez pas avoir plus de 2^16 caractères. UTF-8 offre un compromis raisonnable : tous les caractères ASCII (ASCII 0 à 127) sont représentés sur un octet, ce qui est très bien pour la compatibilité, mais beaucoup plus de caractères sont autorisés.
Comme la plupart des codages à longueur variable, y compris les types de séquences d'échappement présentés ci-dessus, UTF-8 est un code instantané . Cela signifie que le décodeur lit simplement octet par octet et que, dès qu'il atteint le dernier octet d'un caractère, il sait de quoi il s'agit (et il sait qu'il s'agit de l'octet le plus proche). n'est pas le début d'un caractère plus long).
Par exemple, le caractère "A" est représenté par l'octet 65, et il n'existe pas de caractères de deux/trois/quatre octets dont le premier octet est 65. Sinon, le décodeur ne serait pas en mesure de distinguer ces caractères d'un "A" suivi d'autre chose.
Mais UTF-8 est encore plus limité. Il garantit que l'encodage d'un caractère plus court n'apparaîtra jamais partout dans l'encodage d'un caractère plus long. Par exemple, aucun des octets d'un caractère de 4 octets ne peut être 65.
Étant donné que l'UTF-8 compte 128 caractères différents de 1 octet (dont la valeur des octets est comprise entre 0 et 127), tous les caractères de 2, 3 et 4 octets doivent être composés uniquement d'octets compris entre 128 et 256. C'est une restriction importante. Cependant, elle permet aux fonctions de chaîne de caractères orientées octet de fonctionner avec peu ou pas de modifications. Par exemple, la fonction C strstr()
fonctionne toujours comme prévu si ses entrées sont des chaînes UTF-8 valides.
UTF-16
L'UTF-16 est également un code à longueur variable ; ses caractères consomment soit 2 soit 4 octets. Les valeurs de 2 octets dans la plage 0xD800-0xDFFF sont réservées à la construction de caractères de 4 octets, et tous les caractères de 4 octets sont constitués de deux octets dans la plage 0xD800-0xDBFF suivis de 2 octets dans la plage 0xDC00-0xDFFF. Pour cette raison, Unicode n'attribue aucun caractère dans la plage U+D800-U+DFFF.
UTF-32
L'UTF-32 est un code à longueur fixe, chaque caractère ayant une longueur de 4 octets. Bien que cela permette l'encodage de 2^32 caractères différents, seules les valeurs comprises entre 0 et 0x10FFFF sont autorisées dans ce schéma.
Comparaison des capacités :
-
UTF-8 : 2 097 152 (en réalité 2 166 912, mais en raison de détails de conception, certains d'entre eux correspondent à la même chose)
-
UTF-16 : 1,112,064
-
UTF-32 : 4.294.967.296 (mais limité aux 1.114.112 premiers)
Le plus restreint est donc UTF-16 ! La définition formelle d'Unicode a limité les caractères Unicode à ceux qui peuvent être encodés avec UTF-16 (c'est-à-dire la plage U+0000 à U+10FFFF, à l'exclusion de U+D800 à U+DFFF). UTF-8 et UTF-32 supportent tous ces caractères.
Le système UTF-8 est en fait "artificiellement" limité à 4 octets. Il peut être étendu à 8 octets sans violer les restrictions que j'ai décrites précédemment, et cela donnerait une capacité de 2^42. La spécification originale de l'UTF-8 autorisait en fait jusqu'à 6 octets, ce qui donne une capacité de 2^31. Mais RFC 3629 l'a limité à 4 octets, puisque c'est la quantité nécessaire pour couvrir tout ce que fait l'UTF-16.
Il existe d'autres schémas d'encodage Unicode (principalement historiques), notamment UCS-2 (qui n'est capable d'encoder que de U+0000 à U+FFFF).