【问题标题】:C# - How to sort strings that include text and numbersC# - 如何对包含文本和数字的字符串进行排序
【发布时间】:2018-11-10 15:46:56
【问题描述】:

我有一个列表视图,其中包含计算机名和用户名以及一个数字(作为字符串)。我已经使用 IComparer 接口创建了自己的 ListViewItemComparer。但它并没有像我想要的那样正确地对项目进行排序。 这就是它应该如何对计算机进行排序,例如: 计算机-1 计算机-2 电脑-3 ... 计算机 15

这是对它们进行排序的方式: 计算机-1 计算机 10 计算机 11 ... 计算机-2 电脑-3

问题是我不能简单地删除“计算机”部分并比较后面的数字,因为这只是一个示例,计算机名称可以是所有内容(aaa393bbb333、ccccvvvv、222hhhdh、Computer-01、Computer -02,....)

这是我的代码:

 private bool isNumeric(String pInput)
    {
        int o;
        return int.TryParse(pInput, out o);
    }

    public int Compare(object x, object y)
    {
        ListViewItem itemX = x as ListViewItem;
        ListViewItem itemY = y as ListViewItem;
        //
        int returnVal = -1;
        if (itemX == null && itemY == null) returnVal = 0;
        else if (itemX == null) returnVal = -1;
        else if (itemY == null) returnVal = 1;
        else if (itemX.SubItems.Count - 1 < col && itemY.SubItems.Count - 1 < col) returnVal = 0;
        else if (itemX.SubItems.Count - 1 < col) returnVal = -1;
        else if (itemY.SubItems.Count - 1 < col) returnVal = 1;
        else if(isNumeric(itemX.SubItems[col].Text) && isNumeric(itemY.SubItems[col].Text))
        {
            //used for number comparison
            int value1 = int.Parse(itemX.SubItems[col].Text);
            int value2 = int.Parse(itemY.SubItems[col].Text);
            if (value1 == value2) returnVal = 0;
            else if (value1 < value2) returnVal = -1;
            else if (value1 > value2) returnVal = 1;
        }
        else returnVal = String.Compare(itemX.SubItems[col].Text, itemY.SubItems[col].Text);
        if (order == SortOrder.Descending)
            returnVal *= -1;
        return returnVal;
    }

【问题讨论】:

  • 当然你可以从数字中“删掉”计算机名,只是不要忘记它们;-) 当比较两个计算机名时,你首先比较计算机名没有数字的部分。如果它们不同(不相等),那么您现在就得到了所需的比较结果。如果计算机名称部分相同(相等),则您将比较数字部分。因此,即使计算机名称部分相同,现在您也可以获得所需的比较结果...
  • windows 内置了“自然排序”方法。文件资源管理器使用它对字母数字文件名进行排序
  • 感谢您的回答。但是你不理解我。 “Computer-”只是计算机名的一个例子。计算机名称可以是一切。所以计算机名甚至可以是这个 aaaa100aa2。但是我如何将它与其他计算机名称进行比较?
  • @Disaffected 1070452 是的,这正是我想要的。但是我该如何实现呢?
  • 转到您最喜欢的搜索引擎并研究“自然排序”这里已经有几十种解决方案

标签: c# sorting compare string-comparison compareto


【解决方案1】:

你可以使用正则表达式

(?<=\D)(?=\d)|(?<=\d)(?=\D)

将字符串拆分为数字和文本。

string[] parts = Regex.Split(theString, @"(?<=\D)(?=\d)|(?<=\d)(?=\D)");

这会交替生成数字和文本。它是如何工作的:

(?<=exp)pos      Match any position pos following a prefix exp. 
pos(?=exp)       Match any position pos preceding a suffix exp. 

因此,正则表达式的意思是,在文本和数字之间的位置或数字和文本之间的位置分割,其中\D 代表非数字字符,\d 代表数字字符,| 代表 OR。

您将必须测试第一部分是文本还是数字

bool firstIsNumber = Char.IsDigit(parts[0][0]);

如果第一部分是数字,则偶数索引处的所有部分都是数字,奇数索引处的所有部分都是文本,反之亦然。

private static readonly Regex numTextSplitRegex =
    new Regex(@"(?<=\D)(?=\d)|(?<=\d)(?=\D)", RegexOptions.Compiled);

public int Compare(string x, string y)
{
    x = x ?? "";
    y = y ?? "";
    string[] xParts = numTextSplitRegex.Split(x);
    string[] yParts = numTextSplitRegex.Split(y);

    bool firstXIsNumber = xParts[0].Length > 0 && Char.IsDigit(xParts[0][0]);
    bool firstYIsNumber = yParts[0].Length > 0 && Char.IsDigit(yParts[0][0]);

    if (firstXIsNumber != firstYIsNumber) {
        return x.CompareTo(y);
    }

    for (int i = 0; i < Math.Min(xParts.Length, yParts.Length); i++) {
        int result;
        if (firstXIsNumber == (i % 2 == 0)) { // Compare numbers.
            long a = Int64.Parse(xParts[i]);
            long b = Int64.Parse(yParts[i]);
            result = a.CompareTo(b);
        } else { // Compare texts.
            result = xParts[i].CompareTo(yParts[i]);
        }
        if (result != 0) {
            return result;
        }
    }
    return xParts.Length.CompareTo(yParts.Length);
}

【讨论】:

    猜你喜欢
    • 2019-03-28
    • 2016-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-26
    • 2021-08-12
    • 1970-01-01
    相关资源
    最近更新 更多