Wpadam w zaskakujący problem.
Załadowałem plik tekstowy do mojej aplikacji i mam pewną logikę, która porównuje wartość mającą µ.
I zdałem sobie sprawę, że nawet jeśli teksty są takie same, wartość porównania jest fałszywa.
Console.WriteLine("μ".Equals("µ")); // returns false
Console.WriteLine("µ".Equals("µ")); // return true
W dalszej linii wklejany jest znak µ.
Jednak mogą to nie być jedyne postacie, które są takie.
Czy istnieje sposób w C #, aby porównać znaki, które wyglądają tak samo, ale w rzeczywistości są różne?
Odpowiedzi:
W wielu przypadkach można znormalizować oba znaki Unicode do określonej formy normalizacji przed ich porównaniem i powinny być w stanie dopasować. Oczywiście, jakiej formy normalizacji należy użyć, zależy od samych postaci; tylko dlatego, że wyglądają podobnie, niekoniecznie oznacza, że reprezentują tę samą postać. Musisz także rozważyć, czy jest to odpowiednie dla twojego przypadku użycia - zobacz komentarz Jukka K. Korpela.
W tej konkretnej sytuacji, jeśli odniesiesz się do linków w odpowiedzi Tony'ego , zobaczysz, że tabela dla U + 00B5 mówi:
Oznacza to, że U + 00B5, drugi znak w oryginalnym porównaniu, można rozłożyć na U + 03BC, pierwszy znak.
Więc znormalizujesz znaki przy użyciu pełnej dekompozycji zgodności, z formami normalizacji KC lub KD. Oto krótki przykład, który napisałem, aby zademonstrować:
Szczegółowe informacje na temat normalizacji Unicode i różnych form normalizacji patrz
System.Text.NormalizationForm
i spec Unicode .źródło
Ponieważ są to naprawdę różne symbole, nawet jeśli wyglądają tak samo, pierwszy to właściwa litera i ma char,
code = 956 (0x3BC)
a drugi to mikro znak i ma181 (0xB5)
.Bibliografia:
Więc jeśli chcesz je porównać i chcesz, aby były równe, musisz to zrobić ręcznie lub zamienić jeden znak na inny przed porównaniem. Lub użyj następującego kodu:
I Demo
źródło
Oba mają różne kody znaków: zapoznaj się z tym, aby uzyskać więcej informacji
Gdzie pierwszy to:
źródło
W konkretnym przykładzie
μ
(mu) iµ
(mikro znak) ten drugi ma rozkład zgodności z pierwszym, dzięki czemu można znormalizować ciąg naFormKC
lubFormKD
przekształcić mikro znaki na mus.Jednak istnieje wiele zestawów znaków, które wyglądają podobnie, ale nie są równoważne w żadnym formularzu normalizacji Unicode. Na przykład
A
(łaciński),Α
(grecki) iА
(cyrylica). Witryna Unicode zawiera plik confusables.txt z ich listą, który ma pomóc programistom chronić się przed atakami homografów . W razie potrzeby możesz przeanalizować ten plik i zbudować tabelę do „wizualnej normalizacji” łańcuchów.źródło
ToUpper
/ byłobyToLower
trudne do wdrożenia. Musiałbyś"B".ToLower()
byćb
w języku angielskim, aleβ
greckim iв
rosyjskim. Obecnie tylko turecki (bez kropeki
) i kilka innych języków wymaga innych reguł wielkości liter niż domyślne.Wyszukaj oba znaki w bazie danych Unicode i zobacz różnicę .
Jedna to grecka mała litera,
µ
a druga to mikroznakµ
.źródło
EDYTUJ Po połączeniu tego pytania z Jak porównać „μ” i „µ” w C #
Oryginalna odpowiedź opublikowana:
EDYTOWAĆ Po przeczytaniu komentarzy, tak, nie jest dobrze używać powyższej metody, ponieważ może ona dawać złe wyniki dla innego typu danych wejściowych, w tym celu powinniśmy użyć normalizacji z pełną dekompozycją zgodności, jak wspomniano na wiki . (Dzięki odpowiedzi przesłanej przez BoltClock )
Wynik
Podczas czytania informacji w Unicode_equivalence znalazłem
Aby porównać równoważność, powinniśmy normalnie użyć
FormKC
np. Normalizacji NFKC lubFormKD
np. Normalizacji NFKD.Byłem trochę ciekawy, aby dowiedzieć się więcej o wszystkich znakach Unicode, więc stworzyłem próbkę, która będzie iterować po wszystkich znakach Unicode w
UTF-16
i otrzymałem wyniki, które chcę omówićFormC
iFormD
znormalizowane wartości nie były równoważneTotal: 12,118
Character (int value): 192-197, 199-207, 209-214, 217-221, 224-253, ..... 44032-55203
FormKC
iFormKD
znormalizowane wartości nie były równoważneTotal: 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
iFormD
znormalizowana wartość nie były równoważne, tamFormKC
iFormKD
znormalizowane wartości również nie były równoważne, z wyjątkiem tych znaków.
901 '΅', 8129 '῁', 8141 '῍', 8142 '῎', 8143 '῏', 8157 '῝', 8158 '῞'
, 8159 '῟', 8173 '῭', 8174 '΅'
FormKC
iFormKD
znormalizowana wartość nie były równoważne, ale tamFormC
iFormD
znormalizowane wartości były równoważneTotal: 119
Znaki:
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
jeśli spróbująTotal:2081
Characters(int value): 55296-57343, 64976-65007, 65534
Te linki mogą być bardzo pomocne w zrozumieniu, jakie reguły rządzą równoważnością Unicode
źródło
"m".ToUpper().Equals("µ".ToUpper());
i"M".ToUpper().Equals("µ".ToUpper());
jest również prawdziwy. To może być niepożądane.Najprawdopodobniej istnieją dwa różne kody znaków, które tworzą (widocznie) ten sam znak. Chociaż technicznie nie są równe, wyglądają na równe. Spójrz na tabelę znaków i zobacz, czy istnieje wiele instancji tej postaci. Lub wydrukuj kod dwóch znaków w swoim kodzie.
źródło
Pytasz „jak je porównać”, ale nie mówisz nam, co chcesz robić.
Istnieją co najmniej dwa główne sposoby ich porównania:
Albo porównasz je bezpośrednio, jak jesteś, i są różne
Lub możesz użyć Normalizacji zgodności Unicode, jeśli potrzebujesz porównania, które znajdzie je pasujące.
Może jednak wystąpić problem, ponieważ normalizacja zgodności Unicode sprawi, że porównanie wielu innych znaków będzie równe. Jeśli chcesz, aby tylko te dwa znaki były traktowane tak samo, powinieneś rzucić własne funkcje normalizacji lub porównania.
Aby uzyskać bardziej szczegółowe rozwiązanie, musimy znać Twój konkretny problem. W jakim kontekście natknąłeś się na ten problem?
źródło
Jeśli chciałbym być pedantyczny, powiedziałbym, że twoje pytanie nie ma sensu, ale ponieważ zbliżamy się do Bożego Narodzenia, a ptaki śpiewają, przejdę do tego.
Po pierwsze, 2 encje, które próbujesz porównać, to
glyph
s, glif jest częścią zestawu glifów dostarczanych przez coś, co zwykle nazywa się „czcionką”, czymś, co zwykle występuje w postacittf
,otf
lub jakiegoś pliku w formacie jesteś za pomocą.Glify są reprezentacją danego symbolu, a ponieważ są one reprezentacją zależną od określonego zestawu, nie możesz po prostu oczekiwać, że będą miały 2 podobne lub nawet „lepsze” identyczne symbole, to wyrażenie, które nie ma sensu jeśli weźmiesz pod uwagę kontekst, powinieneś przynajmniej określić, jaką czcionkę lub zestaw glifów bierzesz pod uwagę, formułując takie pytanie.
To, co jest zwykle używane do rozwiązania problemu podobnego do tego, z którym się spotykasz, to OCR, zasadniczo oprogramowanie, które rozpoznaje i porównuje glify, jeśli C # zapewnia OCR domyślnie , nie wiem tego, ale ogólnie jest to naprawdę złe pomysł, jeśli tak naprawdę nie potrzebujesz OCR i wiesz, co z nim zrobić.
Możesz skończyć z interpretacją książki o fizyce jako starożytnej greckiej książki, nie wspominając o tym, że OCR są generalnie drogie pod względem zasobów.
Jest powód, dla którego te postacie są zlokalizowane w taki sposób, w jaki są zlokalizowane, po prostu tego nie rób.
źródło
Za pomocą można narysować oba znaki o tym samym stylu i rozmiarze czcionki
DrawString
metody . Po wygenerowaniu dwóch bitmap z symbolami można je porównać piksel po pikselu.Zaletą tej metody jest to, że można porównać nie tylko absolutnie równe znaki, ale także podobne (z określoną tolerancją).
źródło