D J*_*D J 94 .net c# string unicode string-comparison
我陷入了一个令人惊讶的问题.
我在我的应用程序中加载了一个文本文件,并且我有一些逻辑比较了μ的值.
我意识到,即使文本相同,比较值也是错误的.
Console.WriteLine("?".Equals("µ")); // returns false
Console.WriteLine("µ".Equals("µ")); // return true
Run Code Online (Sandbox Code Playgroud)
在后面的行中,字符μ被复制粘贴.
但是,这些可能不是唯一像这样的字符.
在C#中是否有任何方法来比较看起来相同但实际上不同的字符?
Ton*_*ony 149
因为它们实际上是不同的符号,即使它们看起来相同,首先是实际的字母并且有char code = 956 (0x3BC),第二个是微型符号并且具有181 (0xB5).
参考文献:
因此,如果要比较它们并且需要它们相等,则需要手动处理它,或者在比较之前将一个char替换为另一个char.或使用以下代码:
public void Main()
{
var s1 = "?";
var s2 = "µ";
Console.WriteLine(s1.Equals(s2)); // false
Console.WriteLine(RemoveDiacritics(s1).Equals(RemoveDiacritics(s2))); // true
}
static string RemoveDiacritics(string text)
{
var normalizedString = text.Normalize(NormalizationForm.FormKC);
var stringBuilder = new StringBuilder();
foreach (var c in normalizedString)
{
var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
if (unicodeCategory != UnicodeCategory.NonSpacingMark)
{
stringBuilder.Append(c);
}
}
return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
}
Run Code Online (Sandbox Code Playgroud)
和演示
Bol*_*ock 124
在很多情况下,你可以正常化比较之前两个Unicode字符的一定范式,他们应该能够匹配.当然,您需要使用哪种规范化形式取决于角色本身; 仅仅因为它们看起来相似并不一定意味着它们代表相同的角色.您还需要考虑它是否适合您的用例 - 请参阅Jukka K. Korpela的评论.
对于这种特殊情况,如果您参考Tony的答案中的链接,您会看到U + 00B5的表格显示:
分解<compat> GREEK SMALL LETTER MU(U + 03BC)
这意味着原始比较中的第二个字符U + 00B5可以分解为第一个字符U + 03BC.
因此,您将使用完全兼容性分解来标准化字符,标准化形式为KC或KD.这是我写的一个简单示例:
using System;
using System.Text;
class Program
{
static void Main(string[] args)
{
char first = '?';
char second = 'µ';
// Technically you only need to normalize U+00B5 to obtain U+03BC, but
// if you're unsure which character is which, you can safely normalize both
string firstNormalized = first.ToString().Normalize(NormalizationForm.FormKD);
string secondNormalized = second.ToString().Normalize(NormalizationForm.FormKD);
Console.WriteLine(first.Equals(second)); // False
Console.WriteLine(firstNormalized.Equals(secondNormalized)); // True
}
}
Run Code Online (Sandbox Code Playgroud)
有关Unicode正常化细节和不同的标准化形式是指System.Text.NormalizationForm和Unicode的规范.
Vis*_*har 86
它们都有不同的字符代码:有关详细信息,请参阅此处
Console.WriteLine((int)'?'); //956
Console.WriteLine((int)'µ'); //181
Run Code Online (Sandbox Code Playgroud)
在哪里,第一个是:
Display Friendly Code Decimal Code Hex Code Description
====================================================================
? μ μ μ Lowercase Mu
µ µ µ µ micro sign Mu
Run Code Online (Sandbox Code Playgroud)

dan*_*n04 39
对于?(mu)和µ(微信号)的具体示例,后者对前者具有兼容性分解,因此您可以将字符串规范化为FormKC或FormKD将微观符号转换为mus.
但是,有许多字符集看起来很相似,但在任何Unicode规范化形式下都不相同.例如,A(拉丁语),?(希腊语)和?(西里尔语).Unicode网站有一个confusables.txt文件及其列表,旨在帮助开发人员防范同形异义攻击.如有必要,您可以解析此文件并构建一个用于字符串"视觉规范化"的表.
Sub*_*cob 34
搜索Unicode数据库中的两个字符并查看差异.
一个是希腊小写字母 µ,另一个是Micro Sign µ.
Run Code Online (Sandbox Code Playgroud)Name : MICRO SIGN Block : Latin-1 Supplement Category : Letter, Lowercase [Ll] Combine : 0 BIDI : Left-to-Right [L] Decomposition : <compat> GREEK SMALL LETTER MU (U+03BC) Mirror : N Index entries : MICRO SIGN Upper case : U+039C Title case : U+039C Version : Unicode 1.1.0 (June, 1993)
Run Code Online (Sandbox Code Playgroud)Name : GREEK SMALL LETTER MU Block : Greek and Coptic Category : Letter, Lowercase [Ll] Combine : 0 BIDI : Left-to-Right [L] Mirror : N Upper case : U+039C Title case : U+039C See Also : micro sign U+00B5 Version : Unicode 1.1.0 (June, 1993)
dbw*_*dbw 24
编辑此问题合并后如何比较C中的'μ'和'μ'
原始答案发布:
"?".ToUpper().Equals("µ".ToUpper()); //This always return true.
Run Code Online (Sandbox Code Playgroud)
编辑 阅读评论后,是的,使用上述方法并不好,因为它可能会为其他类型的输入提供错误的结果,为此我们应该使用维基中提到的完全兼容性分解进行规范化.(感谢BoltClock发布的答案)
static string GREEK_SMALL_LETTER_MU = new String(new char[] { '\u03BC' });
static string MICRO_SIGN = new String(new char[] { '\u00B5' });
public static void Main()
{
string Mus = "µ?";
string NormalizedString = null;
int i = 0;
do
{
string OriginalUnicodeString = Mus[i].ToString();
if (OriginalUnicodeString.Equals(GREEK_SMALL_LETTER_MU))
Console.WriteLine(" INFORMATIO ABOUT GREEK_SMALL_LETTER_MU");
else if (OriginalUnicodeString.Equals(MICRO_SIGN))
Console.WriteLine(" INFORMATIO ABOUT MICRO_SIGN");
Console.WriteLine();
ShowHexaDecimal(OriginalUnicodeString);
Console.WriteLine("Unicode character category " + CharUnicodeInfo.GetUnicodeCategory(Mus[i]));
NormalizedString = OriginalUnicodeString.Normalize(NormalizationForm.FormC);
Console.Write("Form C Normalized: ");
ShowHexaDecimal(NormalizedString);
NormalizedString = OriginalUnicodeString.Normalize(NormalizationForm.FormD);
Console.Write("Form D Normalized: ");
ShowHexaDecimal(NormalizedString);
NormalizedString = OriginalUnicodeString.Normalize(NormalizationForm.FormKC);
Console.Write("Form KC Normalized: ");
ShowHexaDecimal(NormalizedString);
NormalizedString = OriginalUnicodeString.Normalize(NormalizationForm.FormKD);
Console.Write("Form KD Normalized: ");
ShowHexaDecimal(NormalizedString);
Console.WriteLine("_______________________________________________________________");
i++;
} while (i < 2);
Console.ReadLine();
}
private static void ShowHexaDecimal(string UnicodeString)
{
Console.Write("Hexa-Decimal Characters of " + UnicodeString + " are ");
foreach (short x in UnicodeString.ToCharArray())
{
Console.Write("{0:X4} ", x);
}
Console.WriteLine();
}
Run Code Online (Sandbox Code Playgroud)
产量
INFORMATIO ABOUT MICRO_SIGN
Hexa-Decimal Characters of µ are 00B5
Unicode character category LowercaseLetter
Form C Normalized: Hexa-Decimal Characters of µ are 00B5
Form D Normalized: Hexa-Decimal Characters of µ are 00B5
Form KC Normalized: Hexa-Decimal Characters of µ are 03BC
Form KD Normalized: Hexa-Decimal Characters of µ are 03BC
________________________________________________________________
INFORMATIO ABOUT GREEK_SMALL_LETTER_MU
Hexa-Decimal Characters of µ are 03BC
Unicode character category LowercaseLetter
Form C Normalized: Hexa-Decimal Characters of µ are 03BC
Form D Normalized: Hexa-Decimal Characters of µ are 03BC
Form KC Normalized: Hexa-Decimal Characters of µ are 03BC
Form KD Normalized: Hexa-Decimal Characters of µ are 03BC
________________________________________________________________
Run Code Online (Sandbox Code Playgroud)
在读取Unicode_equivalence中的信息时,我发现了
等价标准的选择会影响搜索结果.例如,一些印刷连字,如U + FB03(ffi),.....因此搜索 U + 0066(f)作为子串将成功进行U + FB03 的NFKC归一化,但不能成为U + FB03的NFC归一化.
因此,为了比较等价,我们通常应该使用FormKC即NFKC归一化或FormKD即NFKD归一化.
我很想知道关于所有Unicode字符的更多信息,所以我制作了可以迭代所有Unicode字符的示例,UTF-16我得到了一些我想讨论的结果
FormC和FormD标准化值不相等的字符的信息Total: 12,118Character (int value): 192-197, 199-207, 209-214, 217-221, 224-253, ..... 44032-55203FormKC和FormKD标准化值不相等的字符的信息Total: 12,245Character (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-65274FormC和FormD标准值是不等价的,还有FormKC和FormKD标准化值也只是这些字符不等同901 '?', 8129 '?', 8141 '?', 8142 '?', 8143 '?', 8157 '?', 8158 '?', 8159 '?', 8173 '?', 8174 '?'FormKC和FormKD标准化值不相等,但那里FormC和FormD标准化值是等价的Total: 119452 '?' 453 '?' 454 '?' 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如果尝试则会抛出Total:2081
Characters(int value): 55296-57343, 64976-65007, 65534这个链接对于理解管理Unicode等价的规则非常有帮助
最有可能的是,有两种不同的字符代码可以(明显地)生成相同的字符.虽然技术上并不相同,但看起来并不相同.查看字符表并查看该字符是否有多个实例.或者在代码中打印出两个字符的字符代码.
你问"如何比较它们",但你没有告诉我们你想做什么.
至少有两种主要方法可以比较它们:
要么直接比较它们,要么它们是不同的
或者,如果需要进行比较以查找匹配,则使用Unicode兼容性规范化.
可能存在问题,因为Unicode兼容性规范化会使许多其他字符比较相等.如果您只想将这两个字符视为相似,则应该使用自己的规范化或比较函数.
对于更具体的解决方案,我们需要了解您的具体问题.您遇到此问题的背景是什么?
如果我想迂腐,我会说你的问题没有意义,但是因为我们正在接近圣诞节并且鸟儿正在唱歌,我将继续这样做.
首先,2个实体您要比较有glyphS,A字形是一组由什么通常知道作为一个"字体"提供的字形,这通常是在一个事物的一部分ttf,otf或任何文件格式,你是使用.
字形是给定符号的表示,并且由于它们是依赖于特定集合的表示,因此您不能期望具有2个相似甚至"更好"的相同符号,这是一个没有意义的短语如果你考虑上下文,你至少应该在你提出这样的问题时指定你正在考虑的字体或字形集.
什么通常用来解决类似于你遇到的问题,它是一个OCR,本质上是一个识别和比较字形的软件,如果C#默认提供OCR我不知道,但它通常是一个非常糟糕的想法,如果你真的不需要OCR,你知道如何处理它.
您最终可能会将物理书籍解读为一本古希腊书籍而不提及OCR在资源方面通常很昂贵的事实.
有一个原因可以解释为什么这些字符的本地化方式是本地化的,只是不这样做.