如何正确地对 DataTable 的字符串数字列进行排序

3

我正在尝试对一个包含字符串数字的列进行排序,例如N1、N10、N100、N2,我期望得到的结果是N1、N2、N10、N100,但是排序不起作用,我得到的值是相同的N1、N10、N100、N2。

我编写了以下代码。

static class ExtensionMethod
{
    public static DataTable SortAlphaNumeric(this DataTable datatable, string columnName)
    {
        return datatable.AsEnumerable()
                  .OrderBy(r => r.Field<String>(columnName), new CustomComparer())
                  .CopyToDataTable();
    }
}

public class CustomComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        var numberX = Regex.Match(x, @"\d+").Value;
        var numberY = Regex.Match(y, @"\d+").Value;

        var alphaX = Regex.Match(x, @"[^a-z]").Value;
        var alphaY = Regex.Match(y, @"[^a-z]").Value;

        if (alphaX.CompareTo(alphaY) == 0)
            return numberX.CompareTo(numberY);
        else if (alphaX.CompareTo(alphaY) < 0)
            return -1;
        return 1;            
    }
}

// Code example
class TestExample
{
    public void Test()
    {
        var dt = new DataTable();
        dt.Columns.Add("AlphaNumeric", Type.GetType("System.String"));
        var row = dt.NewRow();
        row["AlphaNumeric"] = "N1";
        dt.Rows.Add(row);
        row = dt.NewRow();
        row["AlphaNumeric"] = "N10";
        dt.Rows.Add(row);
        row = dt.NewRow();
        row["AlphaNumeric"] = "N100";
        dt.Rows.Add(row);
        row = dt.NewRow();
        row["AlphaNumeric"] = "N2";
        dt.Rows.Add(row);

        var orderedDt = dt.SortAlphaNumeric("AlphaNumeric");
    }
}

alpha 不是 a-z 吗? - Haukinger
我的意思是alpha应该是所有字母A-Z和a-z。它编码错误了吗? - ehh
@AntonínLejsek,好发现,我已经修复了。我刚刚把错误的代码复制到了问题中。谢谢。 - ehh
3个回答

3

您的比较器中的更改:

var numberX = int.Parse(Regex.Match(x, @"\d+").Value);
var numberY = int.Parse(Regex.Match(y, @"\d+").Value);

如果只有像 C99 或者 X10a 这样的字符串,那么这个比较器就足够了。但是如果你需要比较其他部分,你需要一个更复杂的比较器来解析整数部分并进行比较。 - Tim Schmelter
是的,没错。在这个例子中,第一个字母已经被比较了。 - PinBack

1
我会使用(?<alpha>[A-Za-z])(?<number>\d+)作为正则表达式,比较alpha(字符串比较),如果相等,则int.Parse number并进行比较(整数比较)。
这将只执行两个正则表达式,而不是四个(可能将其编译为静态字段会更快),如果比较实际数字,则2会小于10。如果您不解析数字,则可以跳过整个正则表达式,并进行一次字符串比较。

0
如果数字方案是确定性的(始终是一个字符串+一个整数),则可以将它们简单地存储在两个单独的字段中(理想情况下回到数据库。组合键毕竟是一件事)。然后就是“先按字符串排序,再按第二个数字”。
如果不是这样,事情就会变得困难。你想要的是Windows对文件进行的相当不寻常的排序。除了自定义正则表达式解决方案(但如果它是那么确定的话,你可能可以使用2个或更多字段),还有StrCmpLogicalW。但这个方法既不受管理,而且它的行为在Windows之间也有所不同(它是运行在Windows上的“规范”排序,但这种排序在Windows版本之间有所不同)。

btb,这个需要支持ASCII范围之外的Unicode字符吗?我问这个是因为对这些字符串进行排序有一个特殊的规范化问题(https://msdn.microsoft.com/en-us/library/ebza6ck1.aspx)。 - Christopher

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接