为什么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);
给出了期望的结果。
无论如何,我认为你最好将你的排序基于特定的文化,如当前用户的文化(如果可能的话)。