Сортировка строк, содержащих номера удобным для пользователя способом

Будучи привыкшим к стандартным способам сортировки строк, я был удивлен, когда заметил, что Windows сортирует файлы по их именам в некотором роде. Позвольте мне привести вам пример:

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

Я думаю, что эти имена сравниваются (во время сортировки) на основе букв и цифр отдельно.

С другой стороны, следующий список сортируется стандартным образом:
Track1.mp3
Track10.mp3
Track2.mp3
Track20.mp3

Я хотел бы создать сравнительный alogorithm в Delphi, который позволит мне сортировать строки таким же образом. Сначала я подумал, что достаточно будет сравнить последовательные символы двух строк, пока они являются буквами. Когда цифра будет найдена в некоторой позиции обеих строк, я бы прочитал все цифры, следующие за ними, чтобы сформировать число, а затем сравнить числа.

Чтобы дать вам пример, я сравню строки "Track10" и "Track2" следующим образом:
1) читать символы, пока они равны, а в то время как буквы: "трек", "трек"
2) если цифра найдена, прочитайте все следующие цифры: "10", "2"
2a), если они равны, перейдите к 1 или закончите
Десять больше двух, поэтому "Track10" больше, чем "Track2"

Казалось, что все будет в порядке, пока я не увижу, во время моих тестов, что Windows считала "Track010" ниже, чем "Track10" , в то время как я думал, что первый из них был больше, поскольку он был длиннее (не говоря уже о том, что согласно мой алгоритм обе строки были бы равны, что неверно).

Не могли бы вы представить мне, как именно Windows сортирует файлы по именам или, может быть, у вас есть готовый к использованию алгоритм (на любом языке программирования), на котором я мог бы основываться?

Спасибо большое!
Мариуш

Ответы

Ответ 1

Джефф написал статью об этом на Coding Horror. Это называется естественной сортировкой, где вы эффективно обрабатываете группу цифр как один "символ". Существуют реализации на каждом языке под солнцем, но, как ни странно, они обычно не встроены в стандартные библиотеки большинства языков.

Ответ 3

Абсолютно простой способ, я нашел, - это изолировать нужную строку, поэтому в случае 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.

Ответ 4

Мать всех видов:

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