Je tombe dans un problème surprenant.
J'ai chargé un fichier texte dans mon application et j'ai une logique qui compare la valeur ayant µ.
Et j'ai réalisé que même si les textes sont identiques, la valeur de comparaison est fausse.
Console.WriteLine("μ".Equals("µ")); // returns false
Console.WriteLine("µ".Equals("µ")); // return true
Dans la dernière ligne, le caractère µ est copié.
Cependant, ce ne sont peut-être pas les seuls personnages qui ressemblent à ça.
Existe-t-il un moyen en C # de comparer les caractères qui se ressemblent mais qui sont en fait différents?
Réponses:
Dans de nombreux cas, vous pouvez normaliser les deux caractères Unicode dans une certaine forme de normalisation avant de les comparer, et ils devraient pouvoir correspondre. Bien entendu, le formulaire de normalisation à utiliser dépend des caractères eux-mêmes; juste parce qu'ils se ressemblent ne signifie pas nécessairement qu'ils représentent le même personnage. Vous devez également déterminer si cela convient à votre cas d'utilisation - voir le commentaire de Jukka K. Korpela.
Pour cette situation particulière, si vous vous référez aux liens dans la réponse de Tony , vous verrez que le tableau pour U + 00B5 dit:
Cela signifie que U + 00B5, le deuxième caractère de votre comparaison d'origine, peut être décomposé en U + 03BC, le premier caractère.
Vous allez donc normaliser les caractères en utilisant une décomposition de compatibilité complète, avec les formes de normalisation KC ou KD. Voici un exemple rapide que j'ai écrit pour démontrer:
Pour plus de détails sur la normalisation Unicode et les différentes formes de normalisation se référer à
System.Text.NormalizationForm
et la spécification Unicode .la source
Parce que ce sont des symboles vraiment différents même s'ils se ressemblent, le premier est la lettre réelle et a un caractère
code = 956 (0x3BC)
et le second est le micro signe et a181 (0xB5)
.Références:
Donc, si vous voulez les comparer et que vous avez besoin qu'ils soient égaux, vous devez le gérer manuellement ou remplacer un caractère par un autre avant la comparaison. Ou utilisez le code suivant:
Et la démo
la source
Ils ont tous deux des codes de caractères différents: reportez-vous à ceci pour plus de détails
Où, le premier est:
la source
Pour l'exemple spécifique de
μ
(mu) etµ
(micro signe), ce dernier a une décomposition de compatibilité avec le premier, vous pouvez donc normaliser la chaîne enFormKC
ouFormKD
convertir les micro signes en mus.Cependant, il existe de nombreux jeux de caractères qui se ressemblent mais qui ne sont équivalents sous aucune forme de normalisation Unicode. Par exemple,
A
(latin),Α
(grec) etА
(cyrillique). Le site Web Unicode a un fichier confusables.txt avec une liste de ceux-ci, destiné à aider les développeurs à se prémunir contre les attaques homographes . Si nécessaire, vous pouvez analyser ce fichier et créer un tableau pour la «normalisation visuelle» des chaînes.la source
ToUpper
/ToLower
difficile à mettre en œuvre. Vous devrez"B".ToLower()
êtreb
en anglais maisβ
en grec etв
en russe. Dans l'état actuel des choses, seul le turc (sans pointi
) et quelques autres langues ont besoin de règles de casse différentes de celles par défaut.Recherchez les deux caractères dans une base de données Unicode et voyez la différence .
L'un est la lettre minuscule grecque
µ
et l'autre est le micro signeµ
.la source
EDIT Après la fusion de cette question avec Comment comparer 'μ' et 'µ' en C #
La réponse originale publiée:
ÉDITER Après avoir lu les commentaires, oui, il n'est pas bon d'utiliser la méthode ci-dessus car elle peut fournir des résultats erronés pour certains autres types d'entrées, pour cela, nous devrions utiliser normaliser en utilisant la décomposition de compatibilité complète comme mentionné dans le wiki . (Merci à la réponse publiée par BoltClock )
Production
En lisant les informations dans Unicode_equivalence, j'ai trouvé
Donc, pour comparer l'équivalence, nous devrions normalement utiliser
FormKC
normalisation NFKC ou laFormKD
normalisation NFKD.J'étais peu curieux d'en savoir plus sur tous les caractères Unicode, j'ai donc créé un échantillon qui itérerait sur tout le caractère Unicode
UTF-16
et j'ai obtenu des résultats dont je veux discuterFormC
et desFormD
valeurs normalisées ne sont pas équivalentsTotal: 12,118
Character (int value): 192-197, 199-207, 209-214, 217-221, 224-253, ..... 44032-55203
FormKC
et desFormKD
valeurs normalisées ne sont pas équivalentsTotal: 12,245
Character (int value): 192-197, 199-207, 209-214, 217-221, 224-228, ..... 44032-55203, 64420-64421, 64432-64433, 64490-64507, 64512-64516, 64612-64617, 64663-64667, 64735-64736, 65153-65164, 65269-65274
FormC
FormD
valeur normalisée et n'étaient pas équivalents, làFormKC
et lesFormKD
valeurs normalisées n'étaient pas non plus équivalentes sauf ces caractèresCaractères:
901 '΅', 8129 '῁', 8141 '῍', 8142 '῎', 8143 '῏', 8157 '῝', 8158 '῞'
, 8159 '῟', 8173 '῭', 8174 '΅'
FormKC
etFormKD
valeur normalisée ne sont pas équivalents, mais ilFormC
etFormD
valeurs normalisées étaient équivalentesTotal: 119
caractères:
452 'DŽ' 453 'Dž' 454 'dž' 12814 '㈎' 12815 '㈏' 12816 '㈐' 12817 '㈑' 12818 '㈒' 12819 '㈓' 12820 '㈔' 12821 '㈕', 12822 '㈖' 12823 '㈗' 12824 '㈘' 12825 '㈙' 12826 '㈚' 12827 '㈛' 12828 '㈜' 12829 '㈝' 12830 '㈞' 12910 '㉮' 12911 '㉯' 12912 '㉰' 12913 '㉱' 12914 '㉲' 12915 '㉳' 12916 '㉴' 12917 '㉵' 12918 '㉶' 12919 '㉷' 12920 '㉸' 12921 '㉹' 12922 '㉺' 12923 '㉻' 12924 '㉼' 12925 '㉽' 12926 '㉾' 13056 '㌀' 13058 '㌂' 13060 '㌄' 13063 '㌇' 13070 '㌎' 13071 '㌏' 13072 '㌐' 13073 '㌑' 13075 '㌓' 13077 '㌕' 13080 '㌘' 13081 '㌙' 13082 '㌚' 13086 '㌞' 13089 '㌡' 13092 '㌤' 13093 '㌥' 13094 '㌦' 13099 '㌫' 13100 '㌬' 13101 '㌭' 13102 '㌮' 13103 '㌯' 13104 '㌰' 13105 '㌱' 13106 '㌲' 13108 '㌴' 13111 '㌷' 13112 '㌸' 13114 '㌺' 13115 '㌻' 13116 '㌼' 13117 '㌽' 13118 '㌾' 13120 '㍀' 13130 '㍊' 13131 '㍋' 13132 '㍌' 13134 '㍎' 13139 '㍓' 13140 '㍔' 13142 '㍖' .......... ﺋ' 65164 'ﺌ' 65269 'ﻵ' 65270 'ﻶ' 65271 'ﻷ' 65272 'ﻸ' 65273 'ﻹ' 65274'
ArgumentException
s'ils sont essayésTotal:2081
Characters(int value): 55296-57343, 64976-65007, 65534
Ces liens peuvent être vraiment utiles pour comprendre quelles règles régissent l'équivalence Unicode
la source
"m".ToUpper().Equals("µ".ToUpper());
et"M".ToUpper().Equals("µ".ToUpper());
est également vrai. Cela peut ne pas être souhaitable.Très probablement, il existe deux codes de caractères différents qui font (visiblement) le même caractère. Bien que techniquement non égaux, ils semblent égaux. Jetez un œil à la table des caractères et voyez s'il existe plusieurs instances de ce caractère. Ou imprimez le code de caractère des deux caractères de votre code.
la source
Vous demandez "comment les comparer" mais vous ne nous dites pas ce que vous voulez faire.
Il existe au moins deux façons principales de les comparer:
Soit vous les comparez directement tels que vous êtes et ils sont différents
Ou vous utilisez la normalisation de compatibilité Unicode si vous avez besoin d'une comparaison qui les trouve correspondre.
Il pourrait y avoir un problème car la normalisation de la compatibilité Unicode rendra de nombreux autres caractères égaux. Si vous voulez que seuls ces deux caractères soient traités de la même manière, vous devez lancer vos propres fonctions de normalisation ou de comparaison.
Pour une solution plus spécifique, nous devons connaître votre problème spécifique. Quel est le contexte dans lequel vous êtes tombé sur ce problème?
la source
Si je veux être pédant, je dirais que votre question n'a pas de sens, mais puisque nous approchons de Noël et que les oiseaux chantent, je vais continuer.
Tout d'abord, les 2 entités que vous essayez de comparer sont
glyph
s, un glyphe fait partie d'un ensemble de glyphes fournis par ce que l'on appelle généralement une "police", ce qui se présente généralement sous la forme d'unttf
,otf
ou quel que soit le format de fichier que vous êtes en utilisant.Les glyphes sont une représentation d'un symbole donné, et comme ils sont une représentation qui dépend d'un ensemble spécifique, vous ne pouvez pas vous attendre à avoir 2 symboles identiques ou même "meilleurs" identiques, c'est une phrase qui n'a pas de sens si vous considérez le contexte, vous devriez au moins spécifier la police ou le jeu de glyphes que vous envisagez lorsque vous formulez une question comme celle-ci.
Ce qui est généralement utilisé pour résoudre un problème similaire à celui que vous rencontrez, c'est un OCR, essentiellement un logiciel qui reconnaît et compare les glyphes, Si C # fournit un OCR par défaut, je ne le sais pas, mais c'est généralement un très mauvais idée si vous n'avez pas vraiment besoin d'un OCR et que vous savez quoi en faire.
Vous pouvez éventuellement interpréter un livre de physique comme un livre grec ancien sans mentionner le fait que l'OCR coûte généralement cher en termes de ressources.
Il y a une raison pour laquelle ces caractères sont localisés de la manière dont ils sont localisés, mais ne le faites pas.
la source
Il est possible de dessiner les deux caractères avec le même style et la même taille de police avec
DrawString
méthode. Une fois que deux bitmaps avec symboles ont été générés, il est possible de les comparer pixel par pixel.L'avantage de cette méthode est que vous pouvez comparer non seulement des caractères égaux absolus, mais également similaires (avec une tolérance définie).
la source