132 votes

Qu'est-ce que l'UTF-8 normalisé ?

El Projet ICU (qui a aussi maintenant un Bibliothèque PHP ) contient les classes nécessaires pour aider à normaliser les chaînes UTF-8 afin de faciliter la comparaison des valeurs lors de la recherche.

Cependant, j'essaie de comprendre ce que cela signifie pour les applications. Par exemple, dans quels cas dois-je préférer l'"équivalence canonique" à l'"équivalence de compatibilité", ou vice-versa ?

241 votes

Qui sait quelles horreurs se cachent dans le cœur sombre d'un code ?

0 votes

@ObscureRobot Je veux vraiment savoir si ces symboles supplémentaires peuvent avoir des états ou non.

2 votes

@Eonil - Je ne suis pas sûr de ce que signifie "state" dans le contexte de l'unicode.

187voto

Kevin Cathcart Points 3521

Tout ce que vous n'avez jamais voulu savoir sur la normalisation d'Unicode

Normalisation canonique

Unicode comprend plusieurs façons d'encoder certains caractères, notamment les caractères accentués. La normalisation canonique transforme les points de code en une forme d'encodage canonique. Les points de code qui en résultent devraient apparaître identiques aux points de code originaux, à moins que les polices ou le moteur de rendu ne présentent des bogues.

Quand l'utiliser

Comme les résultats semblent identiques, il est toujours sûr d'appliquer la normalisation canonique à une chaîne de caractères avant de la stocker ou de l'afficher, pour autant que vous puissiez tolérer que le résultat ne soit pas identique, bit par bit, à l'entrée.

La normalisation canonique se présente sous 2 formes : NFD et NFC. Les deux sont équivalentes dans le sens où l'on peut convertir entre ces deux formes sans perte. La comparaison de deux chaînes de caractères sous NFC donnera toujours le même résultat que la comparaison sous NFD.

BDNF

NFD a les personnages complètement développés. C'est la forme de normalisation la plus rapide à calculer, mais elle donne lieu à un plus grand nombre de points de code (c'est-à-dire qu'elle utilise plus d'espace).

Si vous voulez simplement comparer deux chaînes de caractères qui ne sont pas déjà normalisées, c'est la forme de normalisation préférée, sauf si vous savez que vous avez besoin d'une normalisation de compatibilité.

NFC

Le NFC recombine les points de code lorsque cela est possible après avoir exécuté l'algorithme NFD. Cela prend un peu plus de temps, mais donne des chaînes de caractères plus courtes.

Normalisation des compatibilités

Unicode inclut également de nombreux caractères qui n'ont pas lieu d'être, mais qui étaient utilisés dans les jeux de caractères existants. Unicode les a ajoutés pour permettre au texte de ces jeux de caractères d'être traité en Unicode, puis d'être reconverti sans perte.

La normalisation de compatibilité les convertit en la séquence correspondante de caractères "réels", et effectue également une normalisation canonique. Les résultats de la normalisation de compatibilité peuvent ne pas sembler identiques aux originaux.

Les caractères qui contiennent des informations de formatage sont remplacés par ceux qui n'en contiennent pas. Par exemple, le caractère est converti en 9 . D'autres n'impliquent pas de différences de formatage. Par exemple, le caractère numéral romain est converti en lettres normales IX .

Évidemment, une fois cette transformation effectuée, il n'est plus possible de revenir sans perte au jeu de caractères d'origine.

Quand utiliser

Le Consortium Unicode suggère de penser à la normalisation de la compatibilité comme une ToUpperCase transformer. C'est quelque chose qui peut être utile dans certaines circonstances, mais il ne faut pas l'appliquer n'importe comment.

Un excellent cas d'utilisation serait celui d'un moteur de recherche, car vous voudriez probablement effectuer une recherche pour 9 pour correspondre .

Une chose que vous ne devriez probablement pas faire est d'afficher le résultat de l'application de la normalisation de la compatibilité à l'utilisateur.

NFKC/NFKD

Le formulaire de normalisation de la compatibilité se présente sous deux formes : NFKD et NFKC. Elles ont la même relation qu'entre NFD et C.

Toute chaîne en NFKC est intrinsèquement aussi en NFC, et il en va de même pour le NFKD et le NFD. Ainsi, NFKD(x)=NFD(NFKC(x)) y NFKC(x)=NFC(NFKD(x)) etc.

Conclusion

En cas de doute, optez pour la normalisation canonique. Choisissez NFC ou NFD en fonction du compromis espace/vitesse applicable, ou en fonction de ce qui est requis par un système avec lequel vous interagissez.

46 votes

Une référence rapide pour se souvenir de la signification des abréviations : NF \= forme normalisée D \= décomposer (décompresser) , C \= composer (compresser) K \= compatibilité (depuis l'obtention du "C").

13 votes

Il est toujours préférable d'utiliser le BDNF pour toutes les chaînes de caractères en entrée et le NFC pour toutes les chaînes de caractères en sortie. C'est bien connu.

4 votes

@tchrist : C'est généralement un bon conseil, sauf dans les rares cas où vous souhaitez que la sortie soit, octet par octet, identique à l'entrée lorsqu'aucune modification n'est effectuée. Il y a d'autres cas où vous voulez que le NFC soit en mémoire ou le NFD sur le disque, mais ils sont l'exception plutôt que la règle.

43voto

Random832 Points 9199

Certains caractères, par exemple une lettre avec un accent (disons, é ) peut être représenté de deux façons - un seul point de code U+00E9 ou la lettre simple suivie d'un accent de combinaison U+0065 U+0301 . La normalisation ordinaire choisira l'une d'entre elles pour toujours la représenter (le point de code unique pour NFC, la forme combinée pour NFD).

Pour les caractères qui peuvent être représentés par plusieurs séquences de caractères de base et de signes de combinaison (par exemple, "s, point en dessous, point au-dessus" plutôt que de mettre point au-dessus puis point en dessous ou d'utiliser un caractère de base qui a déjà l'un des points), le BDNF choisira également l'un d'entre eux (le point en dessous va d'abord, comme cela arrive).

Les décompositions de compatibilité comprennent un certain nombre de caractères qui ne devraient pas être des caractères mais qui le sont parce qu'ils étaient utilisés dans les anciens codages. La normalisation ordinaire ne les unifiera pas (pour préserver l'intégrité de l'aller-retour - ce n'est pas un problème pour les formes de combinaison parce qu'aucun ancien encodage [à l'exception d'une poignée d'encodages vietnamiens] n'utilise les deux), mais la normalisation de compatibilité le fera. Pensez au signe du kilogramme "kg" qui apparaît dans certains encodages d'Asie de l'Est (ou le katakana et l'alphabet demi-largeur/pleine largeur), ou la ligature "fi" dans le MacRoman.

Voir http://unicode.org/reports/tr15/ pour plus de détails.

1 votes

C'est en effet la bonne réponse. Si vous utilisez uniquement la normalisation canonique sur un texte qui provient d'un jeu de caractères hérité, le résultat peut être reconverti dans ce jeu de caractères sans perte. Si vous utilisez la décomposition de compatibilité, vous vous retrouvez sans aucun caractère de compatibilité, mais il n'est plus possible de reconvertir le texte dans le jeu de caractères d'origine sans perte.

13voto

Jerry Coffin Points 237758

Les formes normales (d'Unicode, pas des bases de données) traitent principalement (exclusivement ?) des caractères qui ont des marques diacritiques. Unicode fournit certains caractères avec des signes diacritiques "intégrés", comme U+00C0, "A majuscule latin avec gravure". Le même caractère peut être créé à partir d'un "A majuscule latin" (U+0041) avec un "Accent grave combiné" (U+0300). Cela signifie que même si les deux séquences produisent le même caractère, une comparaison octet par octet montrera qu'elles sont complètement différentes.

La normalisation est une tentative de traiter ce problème. La normalisation garantit (ou du moins tente de le faire) que tous les caractères sont codés de la même manière, soit en utilisant un signe diacritique de combinaison distinct lorsque cela est nécessaire, soit en utilisant un seul point de code lorsque cela est possible. Du point de vue de la comparaison, le choix n'a pas vraiment d'importance - pratiquement toute chaîne normalisée se comparera correctement à une autre chaîne normalisée.

Dans ce cas, "compatibilité" signifie compatibilité avec un code qui suppose qu'un point de code équivaut à un caractère. Si vous avez un tel code, vous voudrez probablement utiliser la forme normale de compatibilité. Bien que je ne l'aie jamais vu indiqué directement, les noms des formes normales impliquent que le consortium Unicode considère qu'il est préférable d'utiliser des signes diacritiques combinés séparés. Cela demande plus d'intelligence pour compter les caractères réels dans une chaîne (ainsi que des choses comme casser une chaîne intelligemment), mais c'est plus versatile.

Si vous utilisez pleinement l'ICU, il y a de fortes chances que vous souhaitiez utiliser la forme normale canonique. Si vous essayez d'écrire vous-même du code qui (par exemple) suppose qu'un point de code équivaut à un caractère, alors vous voulez probablement la forme normale de compatibilité qui rend cela vrai aussi souvent que possible.

0 votes

Donc c'est la partie où le Fonctions des graphèmes entrent alors en jeu. Non seulement le caractère est constitué de plus d'octets que l'ASCII - mais plusieurs séquences peuvent constituer un seul caractère, n'est-ce pas ? (Par opposition au Chaîne MB fonctions.)

4 votes

Non, le principe "un point de code est un caractère" correspond à peu près à NFC (celui avec les marques de combinaison est NFD, et aucun d'entre eux n'est "compatible") - Les normalisations de compatibilité NFKC/NFKD sont une question différente ; la compatibilité (ou le manque de compatibilité) pour les codages hérités qui, par exemple, avaient des caractères séparés pour le mu grec et le "micro" (c'est une question amusante à soulever parce que la version "compatible" est celle qui est dans le bloc Latin 1).

0 votes

@Random832 : Oups, c'est vrai. Je devrais savoir qu'il ne faut pas se fier à sa mémoire alors que je n'ai pas travaillé avec lui depuis un an ou deux.

5voto

NikiC Points 47270

Si deux chaînes unicode sont canoniquement équivalentes, les chaînes sont réellement les mêmes, mais utilisent des séquences unicode différentes. Par exemple, Ä peut être représenté soit par le caractère Ä, soit par une combinaison de A et de .

Si les cordes ne sont que des équivalents de compatibilité, les cordes ne sont pas nécessairement les mêmes, mais elles peuvent être les mêmes dans certains contextes. Par exemple, on pourrait les considérer comme identiques à ff.

Ainsi, si vous comparez des chaînes de caractères, vous devez utiliser l'équivalence canonique, car l'équivalence de compatibilité n'est pas une équivalence réelle.

Mais si vous voulez trier un ensemble de chaînes de caractères, il peut être judicieux d'utiliser l'équivalence de compatibilité, car elles sont presque identiques.

4voto

ObscureRobot Points 4336

La question de savoir si l'équivalence canonique ou l'équivalence de compatibilité est plus pertinente pour vous dépend de votre application. La manière ASCII de penser aux comparaisons de chaînes de caractères correspond approximativement à l'équivalence canonique, mais Unicode représente beaucoup de langues. Je ne pense pas qu'il soit prudent de supposer qu'Unicode code toutes les langues d'une manière qui vous permette de les traiter comme l'ASCII d'Europe occidentale.

Figures 1 et 2 fournissent de bons exemples des deux types d'équivalence. Dans le cadre de l'équivalence de compatibilité, il semble que le même nombre dans la forme sub- et super- script serait comparé égal. Mais je ne suis pas sûr que cela résout le même problème que la forme cursive arabe ou les caractères tournés.

La dure réalité du traitement de texte Unicode est que vous devez réfléchir en profondeur aux exigences de votre application en matière de traitement de texte, puis y répondre du mieux que vous pouvez avec les outils disponibles. Cela ne répond pas directement à votre question, mais une réponse plus détaillée nécessiterait des experts linguistiques pour chacune des langues que vous prévoyez de prendre en charge.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X