Le projet ICU (qui a également maintenant une 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 est-ce que je veux "Equivalence canonique" au lieu de "Equivalence de compatibilité", ou vis-versa?
php
c
unicode
unicode-normalization
Xeoncross
la source
la source
(begin curved line) (char1) (char2) … (charN) (end curved line)
plutôt que ceci:(curved line marker prefix) (char1) (curved line marker prefix) (char2) (curved line marker prefix) (char2)
. En d'autres termes, unité minimale qui peut être rendue?Réponses:
Tout ce que vous ne vouliez jamais savoir sur la normalisation 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 résultants doivent apparaître identiques à ceux d'origine, à l'exception de tout bogue dans les polices ou le moteur de rendu.
Quand utiliser
Étant donné que les résultats semblent identiques, il est toujours prudent d'appliquer la normalisation canonique à une chaîne avant de la stocker ou de l'afficher, tant que vous pouvez tolérer que le résultat ne soit pas bit par bit identique à l'entrée.
La normalisation canonique se présente sous 2 formes: NFD et NFC. Les deux sont équivalents dans le sens où l'on peut convertir entre ces deux formes sans perte. Comparer deux chaînes sous NFC donnera toujours le même résultat que les comparer sous NFD.
NFD
NFD a les personnages entièrement développés. C'est la forme de normalisation la plus rapide à calculer, mais les résultats en plus de points de code (c'est-à-dire utilise plus d'espace).
Si vous souhaitez simplement comparer deux chaînes 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
NFC recombine les points de code lorsque cela est possible après l'exécution de l'algorithme NFD. Cela prend un peu plus de temps, mais entraîne des chaînes plus courtes.
Normalisation de la compatibilité
Unicode comprend également de nombreux caractères qui n'appartiennent vraiment pas, mais qui ont été utilisés dans les anciens jeux de caractères. Unicode les a ajoutés pour permettre au texte de ces jeux de caractères d'être traité comme 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 la compatibilité peuvent ne pas sembler identiques aux originaux.
Les caractères contenant des informations de mise en forme sont remplacés par ceux qui n'en contiennent pas. Par exemple, le caractère
⁹
est converti en9
. D'autres n'impliquent pas de différences de formatage. Par exemple, le caractère numérique romainⅨ
est converti en lettres normalesIX
.Évidemment, une fois cette transformation effectuée, il n'est plus possible de reconvertir sans perte le jeu de caractères d'origine.
Quand utiliser
Le Consortium Unicode suggère de penser à la normalisation de la compatibilité comme une
ToUpperCase
transformation. C'est quelque chose qui peut être utile dans certaines circonstances, mais vous ne devez pas simplement l'appliquer bon gré mal gré.Un excellent cas d'utilisation serait un moteur de recherche, car vous voudriez probablement que la recherche
9
corresponde⁹
.Une chose que vous ne devriez probablement pas faire est d'afficher le résultat de l'application de la normalisation de compatibilité à l'utilisateur.
NFKC / NFKD
Le formulaire de normalisation de compatibilité se présente sous deux formes: NFKD et NFKC. Ils ont la même relation qu'entre NFD et C.
Toute chaîne dans NFKC est intrinsèquement également dans NFC, et il en va de même pour NFKD et NFD. Ainsi
NFKD(x)=NFD(NFKC(x))
, etNFKC(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 quelque chose avec lequel vous interagissez.
la source
NFC(x)=Recompose(NFD(x))
.Certains caractères, par exemple une lettre avec un accent (disons,
é
) peuvent être représentés de deux manières - un point de code uniqueU+00E9
ou la lettre simple suivie d'un accent de combinaisonU+0065 U+0301
. La normalisation ordinaire choisira l'un de ceux-ci pour toujours le représenter (le point de code unique pour NFC, la forme de combinaison pour NFD).Pour les caractères qui pourraient être représentés par plusieurs séquences de caractères de base et combinant des marques (par exemple, "s, point ci-dessous, point au-dessus" vs placer le point au-dessus puis le point en dessous ou en utilisant un caractère de base qui a déjà l'un des points), NFD choisissez également l'un d'entre eux
Les décompositions de compatibilité incluent un certain nombre de caractères qui "ne devraient pas vraiment" être des caractères, mais sont parce qu'ils étaient utilisés dans les encodages hérités. La normalisation ordinaire ne les unifiera pas (pour préserver l'intégrité aller-retour - ce n'est pas un problème pour les formes combinées car aucun encodage hérité [sauf une poignée d'encodages vietnamiens] n'utilisait les deux), mais la normalisation de compatibilité le fera. Pensez comme le 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 MacRoman.
Voir http://unicode.org/reports/tr15/ pour plus de détails.
la source
Les formes normales (d'Unicode, pas de bases de données) traitent principalement (exclusivement?) De caractères qui ont des signes diacritiques. Unicode fournit certains caractères avec des signes diacritiques «intégrés», tels que U + 00C0, «Majuscule latine A avec Grave». Le même caractère peut être créé à partir d'un "Latin Capital A" (U + 0041) avec un "Combining Grave Accent" (U + 0300). Cela signifie que même si les deux séquences produisent le même caractère résultant, un octet par octet la comparaison les montrera comme étant complètement différents.
La normalisation est une tentative pour y remédier. La normalisation garantit (ou du moins essaie de) que tous les caractères sont encodés de la même manière - soit tous en utilisant un signe diacritique de combinaison distinct si nécessaire, soit tous en utilisant un seul point de code dans la mesure du possible. Du point de vue de la comparaison, peu importe le choix que vous choisissez - à peu près n'importe quelle chaîne normalisée se comparera correctement à une autre chaîne normalisée.
Dans ce cas, «compatibilité» signifie la compatibilité avec le code qui suppose qu'un point de code équivaut à un caractère. Si vous avez un code comme celui-là, vous voudrez probablement utiliser la forme normale de compatibilité. Bien que je ne l'ai jamais vu énoncé directement, les noms des formes normales impliquent que le consortium Unicode considère qu'il est préférable d'utiliser des signes diacritiques de combinaison séparés. Cela nécessite 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 est plus polyvalent.
Si vous utilisez pleinement l'ICU, il est probable 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 est égal à un caractère, vous voulez probablement la forme normale de compatibilité qui rend cela vrai aussi souvent que possible.
la source
"o\x{332}\x{303}\x{304}"
, et NFC est"\x{22D}\x{332}"
. Pour le deuxième NFD est"o\x{332}\x{304}\x{303}"
et NFC est"\x{14D}\x{332}\x{303}"
. Cependant, il existe de nombreuses possibilités non canoniques qui leur sont canoniquement équivalentes. La normalisation permet la comparaison binaire de graphèmes canoniquement équivalents.Si deux chaînes Unicode sont canoniquement équivalentes, les chaînes sont vraiment les mêmes, en utilisant uniquement des séquences Unicode différentes. Par exemple, Ä peut être représenté en utilisant le caractère Ä ou une combinaison de A et ◌̈.
Si les chaînes sont uniquement équivalentes à la compatibilité, les chaînes ne sont pas nécessairement les mêmes, mais elles peuvent être identiques dans certains contextes. Par exemple, ff pourrait être considéré comme identique à ff.
Donc, si vous comparez des chaînes, vous devez utiliser l'équivalence canonique, car l'équivalence de compatibilité n'est pas une équivalence réelle.
Mais si vous souhaitez trier un ensemble de chaînes, il peut être judicieux d'utiliser l'équivalence de compatibilité car elles sont presque identiques.
la source
C'est en fait assez simple. UTF-8 a en fait plusieurs représentations différentes du même «caractère». (J'utilise des caractères entre guillemets car ils sont différents par octet, mais pratiquement identiques). Un exemple est donné dans le document lié.
Le caractère "Ç" peut être représenté par la séquence d'octets 0xc387. Mais il peut également être représenté par un
C
(0x43) suivi de la séquence d'octets 0xcca7. Vous pouvez donc dire que 0xc387 et 0x43cca7 sont le même caractère. La raison qui fonctionne, c'est que 0xcca7 est une marque de combinaison; c'est-à-dire qu'il prend le caractère avant lui (unC
ici), et le modifie.Maintenant, en ce qui concerne la différence entre l'équivalence canonique et l'équivalence de compatibilité, nous devons examiner les caractères en général.
Il existe 2 types de caractères, ceux qui transmettent un sens à travers la valeur et ceux qui prennent un autre caractère et le modifient. 9 est un personnage significatif. Un super-script ⁹ prend ce sens et le modifie par présentation. Donc canoniquement, ils ont des significations différentes, mais ils représentent toujours le caractère de base.
L'équivalence canonique est l'endroit où la séquence d'octets rend le même caractère avec la même signification. L'équivalence de compatibilité se produit lorsque la séquence d'octets rend un caractère différent avec la même signification de base (même si elle peut être modifiée). Les 9 et ⁹ sont équivalents de compatibilité puisqu'ils signifient tous les deux "9", mais ne sont pas canoniquement équivalents puisqu'ils n'ont pas la même représentation.
la source
Le fait que l'équivalence canonique ou l'équivalence de compatibilité soit plus pertinente pour vous dépend de votre application. La manière ASCII de penser les comparaisons de chaînes correspond à peu près à l'équivalence canonique, mais Unicode représente de nombreux langages. Je ne pense pas qu'il soit sûr de supposer qu'Unicode encode toutes les langues d'une manière qui vous permet de les traiter comme l'ASCII d'Europe occidentale.
Les figures 1 et 2 donnent de bons exemples des deux types d'équivalence. En équivalence de compatibilité, il semble que le même nombre sous forme de sous-script et de super-script se compare égal. Mais je ne suis pas sûr que cela résout le même problème que la forme arabe cursive ou les caractères pivotés.
La dure vérité du traitement de texte Unicode est que vous devez réfléchir profondément aux exigences de traitement de texte de votre application, puis y répondre aussi bien que possible 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.
la source
Le problème de la comparaison de chaînes : deux chaînes dont le contenu est équivalent pour la plupart des applications peuvent contenir des séquences de caractères différentes.
Voir l'équivalence canonique d'Unicode : si l'algorithme de comparaison est simple (ou doit être rapide), l' équivalence Unicode n'est pas effectuée. Ce problème se produit, par exemple, dans la comparaison canonique XML, voir http://www.w3.org/TR/xml-c14n
Pour éviter ce problème ... Quelle norme utiliser? "UTF8 étendu" ou "UTF8 compact"?
Utilisez "ç" ou "c + ◌̧."?
Le W3C et d'autres (ex. Noms de fichiers ) suggèrent d'utiliser le "composé comme canonique" (prenez en compte C des chaînes plus courtes "les plus compactes") ... Donc,
La norme est C ! en cas de doute, utilisez NFC
Pour l'interopérabilité, et pour les choix de «convention sur la configuration» , la recommandation est l'utilisation de NFC , pour «canoniser» les chaînes externes. Pour stocker du XML canonique, par exemple, stockez-le dans le "FORM_C". Le groupe de travail CSV sur le Web du W3C recommande également NFC (section 7.2).
PS: de "FORM_C" est la forme par défaut dans la plupart des bibliothèques. Ex. dans le normalizer.isnormalized () de PHP .
Le terme « forme de compostion » (
FORM_C
) est utilisé à la fois pour dire que «une chaîne est sous la forme C-canonique» (le résultat d'une transformation NFC) et pour dire qu'un algorithme de transformation est utilisé ... Voir http: //www.macchiato.com/unicode/nfc-faqRemarque: pour tester la normalisation de petites chaînes (références d'entités UTF-8 ou XML pures), vous pouvez utiliser ce convertisseur de test / normalisation en ligne .
la source