C#中的字符串排序问题

Posted

技术标签:

【中文标题】C#中的字符串排序问题【英文标题】:String sorting issue in C# 【发布时间】:2012-03-10 10:18:54 【问题描述】:

我有这样的列表

    List<string> items = new List<string>();
    items.Add("-");
    items.Add(".");
    items.Add("a-");
    items.Add("a.");
    items.Add("a-a");
    items.Add("a.a");

    items.Sort();

    string output = string.Empty;
    foreach (string s in items)
    
        output += s + Environment.NewLine;
    

MessageBox.Show(output);

输出返回为

-
.
a-
a.
a.a
a-a

正如我所期望的那样

-
.
a-
a.
a-a
a.a

知道为什么“a-a”没有出现在“a.a”之前,而“a-”出现在“a”之前。

【问题讨论】:

【参考方案1】:

我怀疑在最后一种情况下,由于特定于文化的设置,“-”会以不同的方式处理(在第一个字符串中可能是“破折号”而不是“减号”)。 MSDN warns 关于这个:

比较使用当前区域性来获取特定区域性 信息,例如大小写规则和字母顺序 个别字符。例如,一种文化可以指定 某些字符组合被视为单个字符, 或以特定方式比较大写和小写字符, 或者一个字符的排序顺序取决于字符 在它之前或之后。

另见this MSDN page:

.NET Framework 使用三种不同的排序方式:单词排序、 字符串排序和序数排序。字排序执行文化敏感 字符串的比较。某些非字母数字字符可能有 分配给他们的特殊权重;例如,连字符 ("-") 可能 分配给它的权重非常小,以便“合作”和“合作” 在排序列表中彼此相邻出现。字符串排序类似于 词排序,除了没有特殊情况;因此,所有 非字母数字符号出现在所有字母数字字符之前。 序数排序根据每个字符串的 Unicode 值比较字符串 字符串的元素。

因此,连字符在默认排序模式下得到特殊处理,以使单词排序更“自然”。

如果你专门打开它,你可以获得“正常”的序数排序:

     Console.WriteLine(string.Compare("a.", "a-"));                  //1
     Console.WriteLine(string.Compare("a.a", "a-a"));                //-1

     Console.WriteLine(string.Compare("a.", "a-", StringComparison.Ordinal));    //1
     Console.WriteLine(string.Compare("a.a", "a-a", StringComparison.Ordinal));  //1

要使用序数比较对原始集合进行排序,请使用:

     items.Sort(StringComparer.Ordinal);

【讨论】:

我想你已经破解了,排序这个词似乎是这里的问题。 @ntziolis:看起来确实是这样。 如果数据在DataTable的DataColumn中,如何指定这个Ordinal比较器 @Satya:您可以将数据从 DataColumn 提取到列表中,然后对其进行排序吗?或者您可以用您的代码示例开始另一个问题?【参考方案2】:

List&lt;&gt; 类的Sort 方法依赖于.NET Framework 的默认string 比较器,它实际上是Thread 的当前CultureInfo 的一个实例。

CultureInfo 指定字符的字母顺序,似乎默认使用的顺序与您期望的顺序不同。

排序时您可以指定一个特定的CultureInfo,一个您知道将符合您的排序要求的样本(德国文化):

var sortCulture = new CultureInfo("de-DE");
items.Sort(sortCulture);

更多信息可以在这里找到:http://msdn.microsoft.com/en-us/library/b0zbh7b6.aspxhttp://msdn.microsoft.com/de-de/library/system.stringcomparer.aspx

【讨论】:

不清楚的是“-”(连字符)在“.”(点)之前,“a-”在“a.”之前;为什么不在“a.a”之前加“a-a”? 理论上,当前的文化可能认为.- 是相同的顺序。 .Sort 方法是“不稳定的”,即不保证相等项的顺序。 我在美国英语上进行了测试,得到了与 OP 相同的结果。即使使用 String.Compare 进行测试,我也从来没有得到 0(等于)。我要么得到-1,要么得到1,这取决于哪个是第一个。所以 .Sort 方法可能不是问题。 我尝试System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); items.Sort();,但结果没有改变 我认为 Yacoder 在他的回答中已经破解了这个案子,这是引入这种特殊处理的词排序事物【参考方案3】:

如果您希望您的字符串排序基于实际字节值而不是当前文化定义的规则,您可以按 Ordinal 排序:

items.Sort(StringComparer.Ordinal);

这将使所有文化中的结果保持一致(但它会在“9”之前产生不直观的“14”排序,这可能是也可能不是您要查找的内容)。

【讨论】:

谢谢 Jared,如果数据在 DataTable DataTable dataTable = new DataTable(); dataTable.Columns.Add("Item", typeof (string)); dataRow = dataTable.NewRow(); dataRow["Item"] = "a-a"; dataTable.Rows.Add(dataRow); dataRow = dataTable.NewRow(); dataRow["Item"] = "a.a"; dataTable.Rows.Add(dataRow); DataRow[] rows = dataTable.Select("", "Item ASC"); 的列中,你能告诉我如何排序吗?

以上是关于C#中的字符串排序问题的主要内容,如果未能解决你的问题,请参考以下文章

C# 与 F# 中的默认排序

c# Dictionary 字典的排序问题,请大家指点

按字符串属性C#对对象列表进行排序[重复]

C# LINQ 匿名类 动态排序

C# - 使用属性名称作为字符串按属性排序的代码[重复]

c# 字典 Dictionary排序问题