我正在使用CaseInsensitiveComparer.DefaultInvariant看到一些非常奇怪的排序行为。以前导连字符“ - ”开头的单词最终排序,就好像连字符不在那里而不是在实际字母前排序,这与其他标点符号一样。
所以给予{“你好”,“。net”,“ - 无”}}我最终得到{“。net”,“hello”,“ - without”}而不是预期的{“ - 无”,“ .net“,”你好“}。
或者,用作测试用例:
[TestMethod]
public void TestMethod1()
{
var rg = new String[] {
"x", "z", "y", "-less", ".net", "- more", "a", "b"
};
Array.Sort(rg, CaseInsensitiveComparer.DefaultInvariant);
Assert.AreEqual(
"- more,-less,.net,a,b,x,y,z",
String.Join(",", rg)
);
}
......失败了:
Assert.AreEqual failed.
Expected:<- more,-less,.net,a,b,x,y,z>.
Actual: <- more,.net,a,b,-less,x,y,z>.
任何想法发生了什么?
看起来,默认情况下,.NET在排序字符串时确实很奇怪,这会导致前导连字符被排序到奇怪的位置,以便合作社和合作社排序在一起。因此,如果你想要你的领导连字词结束,并且开始与另一个标点,你必须告诉它不要:
Array.Sort(rg, (a, b) => String.CompareOrdinal(a, b));
答案 0 :(得分:11)
比较过程使用CultureInfo.InvariantCulture来确定排序顺序和套管规则。字符串比较可能会有不同的结果,具体取决于文化。有关特定于文化的比较的更多信息,请参阅System.Globalization命名空间和编码和本地化。 From here.
有趣的部分:
单词sort对字符串进行文化敏感的比较,其中某些非字母数字Unicode字符可能具有分配给它们的特殊权重。例如,连字符( - )可能具有非常小的权重,因此“coop”和“co-op”在排序列表中彼此相邻。 From here.
答案 1 :(得分:3)
要以您需要的方式对字符串进行排序,您必须创建一个比较器类,使用Compareinfo class比较字符串。这个类允许你指定各种比较方法,最符合你需要的是OrdinalIgnoreCase。
来自MSDN:
忽略的搜索值
比较操作,例如那些 由IndexOf或。执行 LastIndexOf方法,可以产生 意外结果如果值为 搜索被忽略。搜索 如果值为空,则忽略该值 字符串(“”),字符或字符串 由具有代码的字符组成 不考虑的点数 操作因为比较 选项或带代码点的值 没有语言意义。 如果是IndexOf的搜索值 method是一个空字符串,用于 例如,返回值为零。
请注意
如果可能,应用程序 应该使用字符串比较方法 接受CompareOptions值 指定比较的种类 预期。作为基本规则, 面向用户的比较是最好的 通过使用语言服务 选项(使用当前文化), 安全比较应该 指定Ordinal或OrdinalIgnoreCase.specify Ordinal或OrdinalIgnoreCase。
我修改了你的测试用例,并且这个测试用例正确执行:
public class MyComparer:Comparer<string>
{
private readonly CompareInfo compareInfo;
public MyComparer()
{
compareInfo = CompareInfo.GetCompareInfo(CultureInfo.InvariantCulture.Name);
}
public override int Compare(string x, string y)
{
return compareInfo.Compare(x, y, CompareOptions.OrdinalIgnoreCase);
}
}
public class Class1
{
[Test]
public void TestMethod1()
{
var rg = new String[] {
"x", "z", "y", "-less", ".net", "- more", "a", "b"
};
Array.Sort(rg, new MyComparer());
Assert.AreEqual(
"- more,-less,.net,a,b,x,y,z",
String.Join(",", rg)
);
}
}
答案 2 :(得分:2)
我的猜测是,在字母被忽略之前,为了排序的目的,它会立刻出现。当你对单词列表进行排序时,你会希望“国际”和“国际”彼此相邻,不是吗?另一方面,划线本身被认为是重要的。
答案 3 :(得分:0)
排序顺序取决于文化,因此您不能假设字符将按ASCII顺序排序。
http://msdn.microsoft.com/en-us/library/a7zyyk0c.aspx
在您的示例中,“h”(U + 0048)位于“破折号”(U + 2013)之前,因此“hello”将出现在“-less”之前。 “” (U + 002E)在两者之前,所以首先出现“.net”。