以用户友好的方式对包含数字的字符串进行排序

时间:2009-06-20 18:37:24

标签: algorithm sorting text numbers

习惯于对字符串进行排序的标准方法,当我注意到Windows以某种高级方式按名称对文件进行排序时,我感到很惊讶。让我举个例子:

Track1.mp3
Track2.mp3
Track10.mp3
Track20.mp3

我认为这些名称会在字母和数字的基础上进行比较(在排序期间)。

另一方面,以下是以标准方式排序的相同列表:
Track1.mp3
Track10.mp3
Track2.mp3
Track20.mp3

我想在Delphi中创建一个比较算法,让我以相同的方式对字符串进行排序。起初我认为将两个字符串的连续字符进行比较就足够了。当在两个字符串的某个位置找到一个数字时,我会读取它们后面的所有数字以形成一个数字,然后比较这些数字。

举个例子,我会用这种方式比较“Track10”和“Track2”字符串:
1)在相同的字符和字母时读取字符:“Track”,“Track”
2)如果找到一个数字,则读取以下所有数字:“10”,“2”
2a)如果它们相等,则转到1或者完成
十大于两,所以“Track10”大于“Track2”

在我的测试中,我注意到Windows认为“Track010”低于“Track10”时,似乎一切都会好起来,而我认为第一个更长,因为它更长(没有提到根据我的算法两个字符串都是相同的,这是错误的。)

您是否可以向我提供Windows如何按名称对文件进行排序的想法,或者您是否有可以使用的现成算法(使用任何编程语言)?

非常感谢!
马里乌什

3 个答案:

答案 0 :(得分:21)

杰夫在Coding Horror上写了一篇关于此事的文章。这称为natural sorting,您可以将一组数字有效地视为单个“字符”。在阳光下的每种语言中都有实现,但奇怪的是,它通常不是内置于大多数语言的标准库中。

答案 1 :(得分:1)

我发现绝对最简单的方法是隔离你想要的字符串,所以在OP的情况下,Path.GetFileNameWithoutExtension(),删除非数字,转换为int,并排序。使用LINQ和一些扩展方法,它是一个单行。就我而言,我正在进行目录:

Directory.GetDirectories(@"a:\b\c").OrderBy(x => x.RemoveNonDigits().ToIntOrZero())

其中RemoveNonDigits和ToIntOrZero是扩展方法:

public static string RemoveNonDigits(this string value) {
    return Regex.Replace(value, "[^0-9]", string.Empty);
}

public static int ToIntOrZero(this string toConvert) {
    try {
        if (toConvert == null || toConvert.Trim() == string.Empty) return 0;            
        return int.Parse(toConvert);
    } catch (Exception) {
        return 0;
    }
}

扩展方法是我到处使用的常用工具。 YMMV。

答案 2 :(得分:0)

各种各样的母亲:

ls '*.mp3' | sort --version-sort