为什么“-less”在“你好”之后而不是之前排序?

时间:2010-09-09 20:57:02

标签: c# .net sorting

我正在使用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));

4 个答案:

答案 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”。