Comment fonctionne le «codage à largeur variable» UTF-8?

110

Le standard Unicode contient suffisamment de points de code pour que vous ayez besoin de 4 octets pour tous les stocker. C'est ce que fait l'encodage UTF-32. Pourtant, l'encodage UTF-8 les comprime d'une manière ou d'une autre dans des espaces beaucoup plus petits en utilisant quelque chose appelé «encodage à largeur variable».

En fait, il parvient à représenter les 127 premiers caractères de l'US-ASCII en un seul octet qui ressemble exactement au vrai ASCII, vous pouvez donc interpréter beaucoup de texte ascii comme s'il s'agissait de UTF-8 sans rien y faire. Astuce. Alors, comment ça marche?

Je vais poser et répondre à ma propre question ici parce que j'ai juste fait un peu de lecture pour comprendre et j'ai pensé que cela pourrait faire gagner du temps à quelqu'un d'autre. De plus, peut-être que quelqu'un peut me corriger si je me trompe.

dsimard
la source
8
Unicode simple ne nécessite pas 32 bits pour encoder tous ses points de code. Une fois, ils ont prétendu que de nombreux points de code possibles, mais après le décollage de l'UTF-8, ils se sont volontairement limités à 21 bits, de sorte que UTF-8 ne dépassera jamais 4 octets par caractère. Unicode ne nécessite actuellement que 17 bits pour contenir tous les points de code possibles. Sans cette limitation, UTF-8 aurait pu passer à 6 octets par caractère.
Warren Young
@Warren: principalement précis, mais Unicode est un code de 21 bits (U + 0000 à U + 10FFFF).
Jonathan Leffler
2
@Warren: UTF-8 limité à 4 octets aurait pu prendre en charge jusqu'à U + 1FFFFF. La restriction à U + 10FFFF a été faite pour le bien de UTF-16.
dan04
@ dan04 Avons-nous une explication simple sur la façon dont il est limité à U + 10FFFF par UTF-16? Ce serait bien d'en savoir plus à ce sujet.
A-letubby le
@ A-letubby: Parce que les codes de «substitut» UTF-16 sont alloués de telle sorte qu'il y a 1024 substituts de piste et 1024 substituts de piste (et ils ne peuvent être utilisés que par paires), pour faire 2 ^ 20 (environ un million) caractères supplémentaires disponible au-delà du BMP. Ajouté aux 2 ^ 16 caractères disponibles dans le BMP, cela rend 0x110000 caractères possibles.
dan04 le

Réponses:

129

Chaque octet commence par quelques bits qui vous indiquent s'il s'agit d'un point de code à un octet, d'un point de code à plusieurs octets ou à la continuation d'un point de code à plusieurs octets. Comme ça:

0xxx xxxx    A single-byte US-ASCII code (from the first 127 characters)

Les points de code multi-octets commencent chacun par quelques bits qui disent essentiellement "hé, vous devez également lire l'octet suivant (ou deux, ou trois) pour comprendre ce que je suis." Elles sont:

110x xxxx    One more byte follows
1110 xxxx    Two more bytes follow
1111 0xxx    Three more bytes follow

Enfin, les octets qui suivent ces codes de démarrage ressemblent tous à ceci:

10xx xxxx    A continuation of one of the multi-byte characters

Puisque vous pouvez dire quel type d'octet vous regardez à partir des premiers bits, alors même si quelque chose est mutilé quelque part, vous ne perdez pas toute la séquence.

dsimard
la source
14
Il y a plus à l'histoire que cela - parce que le codage doit être le codage le plus court possible pour le caractère, ce qui finit par signifier que les octets 0xC0 et 0xC1 ne peuvent pas apparaître en UTF-8, par exemple; et, en fait, 0xF5..0xFF non plus. Consultez la FAQ UTF-8 sur unicode.org/faq/utf_bom.html ou unicode.org/versions/Unicode5.2.0/ch03.pdf
Jonathan Leffler
2
Pourquoi ne pouvait-il pas utiliser un seul caractère pour dire next char is continuation? Si nous avons un caractère de 3 octets, ce serait comme:, 1xxxxxxx 1xxxxxxx 0xxxxxxxdonc moins d'espace serait gaspillé.
9
@Soaku cela fait de l'UTF-8 un code dit "auto-synchronisant". Cela signifie que si, en raison d'erreurs, des parties de la séquence sont manquantes, il est possible de détecter cela et d'éliminer tout ce qui a été brouillé. Si vous lisez un octet qui commence par 10xx, et qu'il n'y a pas d'octet "start" précédent, vous pouvez le supprimer car il n'a pas de sens. Si vous aviez un système comme vous l'avez décrit et que l'un des premiers octets est perdu, vous pourriez vous retrouver avec un caractère différent et valide sans aucune indication d'erreur. Cela permettra également de localiser facilement le prochain caractère valide, ainsi que de corriger les octets de "continuation" manquants.
htmlcoderexe
9

RFC3629 - UTF-8, un format de transformation ISO 10646 est l'autorité finale ici et a toutes les explications.

En bref, plusieurs bits dans chaque octet de la séquence de 1 à 4 octets codée en UTF-8 représentant un seul caractère sont utilisés pour indiquer s'il s'agit d'un octet de fin, d'un octet de début et, si oui, combien d'octets suivent. Les bits restants contiennent la charge utile.

Azheglov
la source
1
Ummmm, idiot moi, je pensais que le standard Unicode était l'autorité finale sur UTF-8
John Machin
6
La norme Unicode définit l'Unicode lui-même. Il ne définit pas diverses méthodes, actuelles et futures, qui peuvent être utilisées pour encoder des textes Unicode à diverses fins (telles que le stockage et le transport). UTF-8 est l'une de ces méthodes et la référence ci-dessus est au document qui la définit.
azheglov
1
RFC3629, page 3, section 3. dit "UTF-8 est défini par la norme Unicode".
John Machin
La recherche de liens sur unicode.org m'a amené à la section 3.9 du standard Unicode et plus précisément à la définition D92 (et aussi tangentiellement D86). Je n'ai aucune idée dans quelle mesure ce lien sera utile lorsque de nouvelles versions seront publiées, mais j'imagine qu'ils veulent garder les identificateurs de section et de définition stables d'une version à l'autre.
tripleee
4

UTF-8 était un autre système pour stocker votre chaîne de points de code Unicode, ces nombres U + magiques, en mémoire en utilisant des octets de 8 bits. En UTF-8, chaque point de code de 0 à 127 est stocké dans un seul octet. Seuls les points de code 128 et plus sont stockés en utilisant 2, 3, en fait jusqu'à 6 octets.

Extrait du minimum absolu que chaque développeur de logiciel doit absolument et positivement savoir sur l'Unicode et les jeux de caractères (sans excuses!)

Andrew
la source
C'est un bon article, mais il semble que Joel se trompe en ce qui concerne la longueur maximale de la séquence; la page Wikipédia n'affiche que 1 à 4 octets par caractère.
détendez-vous
4
Comme je l'ai dit ci-dessus, lorsque UTF-8 a été créé pour la première fois, Unicode revendiquait jusqu'à 32 bits pour les points de code, non pas parce qu'ils en avaient vraiment besoin, uniquement parce que 32 bits est une valeur pratique et qu'ils avaient déjà dépassé le limite précédente de caractères 16 bits. Après que UTF-8 se soit avéré populaire, ils ont choisi de limiter à jamais le nombre maximum de points de code à 2 ^ 21, c'est la plus grande valeur que vous pouvez encoder avec 4 octets du schéma UTF-8. Il y a toujours moins de 2 ^ 17 caractères en Unicode, nous pouvons donc plus que quadrupler le nombre de caractères en Unicode avec ce nouveau schéma.
Warren Young
Ok mais pas l'explication demandée par OP.
Nishant le
2
Cela ne répond pas à la question.
Koray Tugay