Eu caio em um problema surpreendente.
Carreguei um arquivo de texto no meu aplicativo e tenho uma lógica que compara o valor com µ.
E percebi que mesmo que os textos sejam os mesmos, o valor de comparação é falso.
Console.WriteLine("μ".Equals("µ")); // returns false
Console.WriteLine("µ".Equals("µ")); // return true
Na linha posterior, o caractere µ é copiado e colado.
No entanto, esses podem não ser os únicos personagens assim.
Existe alguma maneira em C # para comparar os caracteres que parecem iguais, mas são realmente diferentes?
Respostas:
Em muitos casos, você pode normalizar ambos os caracteres Unicode para uma determinada forma de normalização antes de compará-los, e eles devem ser compatíveis. Claro, qual forma de normalização você precisa usar depende dos próprios personagens; só porque eles são parecidos não significa necessariamente que representem o mesmo personagem. Você também precisa considerar se é apropriado para seu caso de uso - veja o comentário de Jukka K. Korpela.
Para esta situação particular, se você consultar os links na resposta de Tony , verá que a tabela para U + 00B5 diz:
Isso significa que U + 00B5, o segundo caractere em sua comparação original, pode ser decomposto em U + 03BC, o primeiro caractere.
Portanto, você normalizará os caracteres usando a decomposição de compatibilidade total, com os formulários de normalização KC ou KD. Aqui está um exemplo rápido que escrevi para demonstrar:
Para mais detalhes sobre Unicode normalização e as diferentes formas de normalização referem-se
System.Text.NormalizationForm
e a especificação Unicode .fonte
Porque são símbolos realmente diferentes, mesmo que pareçam iguais, o primeiro é a letra real e tem char
code = 956 (0x3BC)
e o segundo é o micro-sinal e tem181 (0xB5)
.Referências:
Então, se você quiser compará-los e precisar que eles sejam iguais, você precisa lidar com isso manualmente ou substituir um caractere por outro antes da comparação. Ou use o seguinte código:
E a demonstração
fonte
Ambos têm códigos de caracteres diferentes: consulte isto para obter mais detalhes
Onde, o primeiro é:
fonte
Para o exemplo específico de
μ
(mu) eµ
(micro sinal), o último tem uma decomposição de compatibilidade com o primeiro, então você pode normalizar a string paraFormKC
ouFormKD
para converter os microssinais em mus.No entanto, existem muitos conjuntos de caracteres que se parecem, mas não são equivalentes em nenhuma forma de normalização Unicode. Por exemplo,
A
(latim),Α
(grego) eА
(cirílico). O site Unicode tem um arquivo confusables.txt com uma lista deles, com o objetivo de ajudar os desenvolvedores a se protegerem contra ataques homográficos . Se necessário, você pode analisar esse arquivo e construir uma tabela para “normalização visual” de strings.fonte
ToUpper
/ToLower
dificultaria a implementação. Você precisa"B".ToLower()
estarb
em inglês, masβ
em grego eв
em russo. Como está, apenas o turco (sem pontoi
) e alguns outros idiomas precisam de regras de capitalização diferentes do padrão.Pesquise os dois caracteres em um banco de dados Unicode e veja a diferença .
Uma é a minúscula letra grega
µ
e a outra é o micro sinalµ
.fonte
EDITAR Após a fusão desta questão com Como comparar 'μ' e 'µ' em C #
Resposta original postada:
EDITAR Depois de ler os comentários, sim, não é bom usar o método acima porque pode fornecer resultados errados para algum outro tipo de entrada, para isso devemos usar normalizar usando decomposição de compatibilidade total conforme mencionado no wiki . (Graças à resposta postada por BoltClock )
Resultado
Ao ler informações em Unicode_equivalence , encontrei
Portanto, para comparar a equivalência, devemos normalmente usar
FormKC
normalização NFKC ouFormKD
normalização NFKD.Eu estava um pouco curioso para saber mais sobre todos os caracteres Unicode, então fiz uma amostra que iteraria sobre todos os caracteres Unicode
UTF-16
e obtive alguns resultados que gostaria de discutirFormC
eFormD
valores normalizados não eram equivalentesTotal: 12,118
Character (int value): 192-197, 199-207, 209-214, 217-221, 224-253, ..... 44032-55203
FormKC
eFormKD
valores normalizados não eram equivalentesTotal: 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
eFormD
normalizada valor não eram equivalentes, nãoFormKC
eFormKD
valores normalizados também não foram equivalentes, exceto esses personagensPersonagens:
901 '΅', 8129 '῁', 8141 '῍', 8142 '῎', 8143 '῏', 8157 '῝', 8158 '῞'
, 8159 '῟', 8173 '῭', 8174 '΅'
FormKC
eFormKD
valor normalizado não foram equivalentes, mas láFormC
eFormD
normalizados valores foram equivalentesTotal: 119
Personagens:
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
se tentadosTotal:2081
Characters(int value): 55296-57343, 64976-65007, 65534
Esses links podem ser realmente úteis para entender quais regras regem a equivalência Unicode
fonte
"m".ToUpper().Equals("µ".ToUpper());
e"M".ToUpper().Equals("µ".ToUpper());
também é verdadeiro. Isso pode não ser desejável.Provavelmente, existem dois códigos de caracteres diferentes que fazem (visivelmente) o mesmo caractere. Embora tecnicamente não sejam iguais, eles parecem iguais. Dê uma olhada na tabela de personagens e veja se existem várias instâncias desse personagem. Ou imprima o código de caractere dos dois caracteres em seu código.
fonte
Você pergunta "como compará-los", mas não nos diz o que deseja fazer.
Existem pelo menos duas maneiras principais de compará-los:
Ou você os compara diretamente como você é e eles são diferentes
Ou você usa a normalização de compatibilidade Unicode se precisar de uma comparação que os encontre correspondentes.
Pode haver um problema porque a normalização da compatibilidade Unicode fará com que muitos outros caracteres sejam comparados da mesma forma. Se você deseja que apenas esses dois caracteres sejam tratados como iguais, você deve rolar suas próprias funções de normalização ou comparação.
Para uma solução mais específica, precisamos saber seu problema específico. Qual é o contexto em que você se deparou com esse problema?
fonte
Se eu quisesse ser pedante, diria que sua pergunta não faz sentido, mas como estamos nos aproximando do Natal e os pássaros cantando, vou prosseguir.
Primeiro, as 2 entidades que você está tentando comparar são
glyph
s, um glifo é parte de um conjunto de glifos fornecidos por aquilo que é normalmente conhecido como uma "fonte", a coisa que geralmente vem em umttf
,otf
ou qualquer formato de arquivo que você está usando.Os glifos são uma representação de um determinado símbolo e, uma vez que são uma representação que depende de um conjunto específico, você não pode esperar ter 2 símbolos semelhantes ou mesmo "melhores" idênticos, é uma frase que não faz sentido se você considerar o contexto, deve pelo menos especificar que fonte ou conjunto de glifos está considerando ao formular uma pergunta como esta.
O que geralmente é usado para resolver um problema semelhante ao que você está encontrando, é um OCR, essencialmente um software que reconhece e compara glifos. Se C # fornece um OCR por padrão, não sei disso, mas geralmente é muito ruim ideia se você realmente não precisa de um OCR e sabe o que fazer com ele.
Você pode acabar interpretando um livro de física como um livro grego antigo, sem mencionar o fato de que OCR geralmente são caros em termos de recursos.
Há uma razão pela qual esses caracteres são localizados da maneira como são localizados, apenas não faça isso.
fonte
É possível desenhar ambos os caracteres com o mesmo estilo de fonte e tamanho com o
DrawString
método. Após a geração de dois bitmaps com símbolos, é possível compará-los pixel a pixel.A vantagem desse método é que você pode comparar não apenas caracteres absolutamente iguais, mas também semelhantes (com tolerância definida).
fonte