为什么string.Compare似乎不一致地处理重音字符?

如果我执行以下语句:

string.Compare("mun", "mün", true, CultureInfo.InvariantCulture) 

结果为’-1’,表示’mun’的数值低于’mün’。

但是,如果我执行此语句:

 string.Compare("Muntelier, Schweiz", "München, Deutschland", true, CultureInfo.InvariantCulture) 

我得到’1’,表明’Muntelier,Schewiz’应该排在最后。

这是比较中的错误吗? 或者,更有可能的是,在排序包含重音的字符串时,我应该考虑一个规则


这是一个问题的原因是,我正在排序一个列表然后做一个手动二进制filter,这意味着让每个字符串以’xxx’开头。

以前我使用的是Linq’Fhere’方法,但现在我必须使用另一个人编写的这个自定义函数,因为他说它表现得更好。

但是自定义函数似乎没有考虑.NET具有的“unicode”规则。 因此,如果我告诉它过滤’mün’,它就找不到任何项目,即使列表中的项目以’mun’开头。

这似乎是因为重音字符的排序不一致,这取决于重音字符后面的字符。


好的,我想我已经解决了这个问题。

在filter之前,我根据每个字符串的前n个字母进行排序,其中n是搜索字符串的长度。

工作中有一个打破平局的算法,请参阅http://unicode.org/reports/tr10/

为了解决语言敏感排序的复杂性,采用了多级比较算法。 例如,在比较两个单词时,最重要的特征是基本字符:例如A和B之间的差异。如果基本字母有任何差异,则通常会忽略重音差异。 如果基数或重音有任何差异,则通常会忽略大小写差异(大写与小写)。 标点符号是可变的。 在某些情况下,标点符号被视为基本字符。 在其他情况下,如果存在任何基础,重音或大小写差异,则应忽略它。 也可能存在最终的打破平局级别,如果字符串中根本没有其他差异,则使用(标准化的)代码点顺序。

因此,“Munt ……”和“Münc…”按字母顺序不同,并根据“t”和“c”排序。

然而,“mun”和“mün”在字母上是相同的(“u”等于“ü”在丢失的语言中)所以比较字符代码

看起来重音字符仅用于某种​​“打破平局”的情况 – 换句话说,如果字符串在其他方面相同。

以下是一些示例代码:

 using System; using System.Globalization; class Test { static void Main() { Compare("mun", "mün"); Compare("muna", "münb"); Compare("munb", "müna"); } static void Compare(string x, string y) { int result = string.Compare(x, y, true, CultureInfo.InvariantCulture)); Console.WriteLine("{0}; {1}; {2}", x, y, result); } } 

(我也尝试在“n”之后添加一个空格,看它是否在字边界上完成 – 它不是。)

结果:

 mun; mün; -1 muna; münb; -1 munb; müna; 1 

我怀疑各种复杂的Unicode规则是正确的 – 但我对它们知之甚少。

至于你是否需要考虑到这一点……我不希望如此。 这是怎么回事?

据我所知,它仍然有些一致。 当使用CultureInfo.InvariantCulture进行比较时,变音字符ü被视为非重音字符u

由于第一个示例中的字符串显然不相等,结果将不是0而是-1(这似乎是默认值)。 在第二个例子中, Muntelier排在最后,因为t跟随字母表中的c

我在MSDN中找不到任何明确的文档解释这些规则,但我发现了

 string.Compare("mun", "mün", CultureInfo.InvariantCulture, CompareOptions.StringSort); 

 string.Compare("Muntelier, Schweiz", "München, Deutschland", CultureInfo.InvariantCulture, CompareOptions.StringSort); 

给出了期望的结果。

无论如何,我认为你最好将你的排序基于特定的文化,如当前用户的文化(如果可能的话)。