Pourquoi UTF-8 gaspille plusieurs bits dans son encodage

17

Selon l'article de Wikipedia , UTF-8 a ce format:

Premier code Dernier code Octets Octet 1 Octet 2 Octet 3 Octet 4
point point Utilisé
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 07FF 2 110xxxxx 10xxxxxx
U + 0800 U + FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
U + 10000 U + 1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
x signifie que ce bit est utilisé pour sélectionner le point de code.

Cela gaspille deux bits sur chaque octet de continuation et un bit dans le premier octet. Pourquoi UTF-8 n'est-il pas encodé comme suit?

Premier code Dernier code Octets Octet 1 Octet 2 Octet 3
point point Utilisé
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 3FFF 2 10xxxxxx xxxxxxxx
U + 0800 U + 1FFFFF 3 110xxxxx xxxxxxxx xxxxxxxx

Il enregistrerait un octet lorsque le point de code est hors du plan multilingue de base ou si le point de code est dans la plage [U + 800, U + 3FFF].

Pourquoi UTF-8 n'est-il pas encodé de manière plus efficace?

qbt937
la source
3
cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt L'encodage que vous proposez est similaire à la proposition FSS / UTF d'origine. Ken Thompson et Rob Pike voulaient la propriété d'auto-synchronisation.
ninjalj
4
En outre, votre codage ne semble pas garantir que les valeurs de code ASCII n'apparaissent dans aucune partie de la représentation des caractères non ASCII. FSS / UTF et UTF-8 sont conçus pour fonctionner avec les programmes hérités, (par exemple: ceux utilisant ASCII NUL et slash (chemin séparateur) comme séparateurs).
ninjalj

Réponses:

26

Ceci est fait pour que vous puissiez détecter quand vous êtes au milieu d'une séquence multi-octets. Lorsque vous regardez les données UTF-8, vous savez que si vous voyez 10xxxxxx, que vous êtes au milieu d'un caractère multi-octets, et que vous devez sauvegarder dans le flux jusqu'à ce que vous voyiez soit 0xxxxxxou 11xxxxxx. En utilisant votre schéma, les octets 2 ou 3 pourraient facilement se retrouver avec des motifs tels que 0xxxxxxxou11xxxxxx

Gardez également à l'esprit que la quantité enregistrée varie entièrement en fonction du type de données de chaîne que vous encodez. Pour la plupart des textes, même les textes asiatiques, vous verrez rarement, voire jamais, des caractères de quatre octets avec du texte normal. De plus, les estimations naïves des gens sur l'apparence du texte sont souvent fausses. J'ai un texte localisé pour UTF-8 qui comprend des chaînes japonaises, chinoises et coréennes, mais c'est en fait le russe qui prend le plus de place. (Parce que nos chaînes asiatiques ont souvent des caractères romains intercalés pour les noms propres, la ponctuation et autres et parce que le mot chinois moyen est de 1 à 3 caractères tandis que le mot russe moyen est beaucoup, beaucoup plus.)

Gort le robot
la source
Mais avec moi, si vous commencez à un endroit connu pour être à la mendicité d'un caractère, vous pouvez dire combien d'octets se trouvent dans le caractère et passer à la mendicité du caractère suivant.
qbt937
11
Sûr. Votre schéma est plus dense en informations mais n'a pas de fonctionnalité importante fournie par UTF-8. En général, les gens préfèrent la sécurité, c'est pourquoi UTF-8 est possible. De plus, pour vraiment prouver que votre schéma est réellement plus efficace, vous voudriez fournir des statistiques en utilisant du texte réel. Vous trouverez peut-être que dans la plupart des textes réels, votre schéma enregistre un montant très trivial et que les économies n'en valent donc pas la peine.
Gort the Robot
3
Une autre caractéristique importante: s'il n'y a pas de point de code zéro intégré, il n'y a pas de zéros intégrés dans la chaîne.
Déduplicateur
Pour le script thaï, vous devez autoriser 4 octets par caractère imprimé. Non seulement ils sont arrivés en retard à la fête et ont donc obtenu un groupe de codes numérotés. Beaucoup de choses qui ressemblent à un seul caractère lors de l'impression sont en fait composées de trois caractères Unicode différents.
James Anderson
@ qbt937: En utilisant votre schéma, comment analyser rapidement pour savoir si une chaîne en contient une autre?
supercat
6

La manière officielle permet au décodeur de savoir quand il est au milieu du tuple et il sait ignorer les octets (ou revenir en arrière) jusqu'à ce que l'octet commence par 0ou 11; cela empêche les valeurs inutiles lorsqu'un seul octet est corrompu.

monstre à cliquet
la source
3

Réponse courte, votre proposition ne fait pas de distinction entre le premier octet et les octets de continuation.

Le modèle de bits à l'extrémité supérieure du premier octet vous indique avec combien d'octets le caractère réel est construit. Ces modèles fournissent également une reconnaissance des erreurs lors de l'analyse d'une chaîne. Si vous lisez (apparemment) le premier octet d'un caractère et que vous obtenez 10xxxxxx, vous savez que vous n'êtes pas synchronisé.

Kitana
la source
2

Ce qui n'a pas été mentionné, c'est que si vous avez une séquence correcte de points de code et un pointeur qui est garanti pour pointer vers le premier octet d'un point de code, avec UTF-8, vous pouvez très facilement trouver le pointeur vers le premier octet du point de code précédent (ignorer tous les octets commençant par 01xx xxxx). Avec votre encodage, c'est impossible sans potentiellement examiner tous les octets jusqu'au début de la chaîne.

Considérons les séquences de (2n + 2) octets

0xxxxxxx
n times (10xxxxxx, 10xxxxxx)
0xxxxxxx

et

n times (10xxxxxx, 10xxxxxx)
(10xxxxxx, 0xxxxxxx)

Si vous avez un pointeur sur le premier octet du premier point de code après cette séquence, vous devez examiner tous les octets pour savoir si le dernier point de code est 0xxxxxxx ou (10xxxxxx, 0xxxxxxx).

Il existe en fait des schémas de codage plus efficaces, où le passage au point de code précédent peut se faire en temps constant, et les pointeurs vers le milieu d'un point de code peuvent être fixés. Autorisez les codes suivants:

X where X < 128
YX where 128 ≤ Y < 236, X < 128
ZYY where 236 ≤ Z < 256, 0 ≤ Y < 236. 

Si l'un des trois octets précédents est ≥ 236, c'est le début d'une séquence de 3 octets, car il ne peut y avoir deux de ces octets dans une séquence de 3 octets valide. Sinon, si l'un des deux octets précédents est ≥ 128, c'est le début d'une séquence de deux octets. Sinon, l'octet précédent est un seul octet <128.

La recherche d'une sous-chaîne devient légèrement plus difficile. Vous souhaiterez peut-être exclure zéro octet afin qu'une chaîne ne contienne un octet nul que si elle contient un point de code zéro.

gnasher729
la source
Ce qui n'a pas été mentionné… - pas vraiment car cela découle directement de l'observation faite dans la réponse de @ratchet freak.
Piotr Dobrogost