Python сортирует «u11-Phrase 1000.wav» перед «u11-Phrase 101.wav»; как я могу преодолеть это? - PullRequest
6 голосов
/ 21 декабря 2009

Я использую Python 2.5 (r25: 51908, 19 сентября 2006 г., 09:52:17) [MSC v.1310 32 бит (Intel)] на win 32

Когда я спрашиваю Python

>>> "u11-Phrase 099.wav" <  "u11-Phrase 1000.wav"
True

Отлично. Когда я спрашиваю

>>> "u11-Phrase 100.wav" <  "u11-Phrase 1000.wav"
True

Это тоже хорошо. Но , когда я спрашиваю

>>> "u11-Phrase 101.wav" <  "u11-Phrase 1000.wav"
False

Таким образом, согласно Python, «u11-Phrase 100.wav» предшествует «u11-Phrase 1000.wav», а «u11-Phrase 101.wav» следует после «u11-Phrase 1000.wav»! И это проблематично для меня, потому что я пытаюсь написать программу переименования файлов, и такая сортировка нарушает функциональность.

Что я могу сделать, чтобы преодолеть это? Должен ли я написать свою собственную функцию cmp и протестировать ее на крайние случаи, или есть намного более простой ярлык, чтобы дать мне нужный порядок?

С другой стороны, если я изменю строки, такие как

>>> "u11-Phrase 0101.wav" <  "u11-Phrase 1000.wav"
True

Однако эти строки взяты из списка файлов каталога, например:

files = glob.glob('*.wav')
files.sort()
for file in files:
    ...

Так что я бы предпочел не делать хирургические операции на струнах после того, как они были созданы glob. И нет, я тоже не хочу менять оригинальные имена файлов в этой папке.

Есть подсказки?

Ответы [ 2 ]

16 голосов
/ 21 декабря 2009

Вы ищете сортировку людей .

Причина, по которой 101.wav не меньше 1000.wav, состоит в том, что компьютеры (не только Python) сортируют строки символ за символом, и первое различие между этими двумя строками заключается в том, что первая строка имеет «1», а вторая Строка имеет «0». «1» не меньше чем «0», поэтому строки сравниваются, как вы видели.

Люди естественным образом разбирают эти строки в свои компоненты и интерпретируют числа численно, а не лексически. Код, на который я ссылался выше, будет выполнять такой же анализ.

9 голосов
/ 21 декабря 2009

Вам необходимо создать правильный ключ сортировки для каждого имени файла. Что-то вроде этого должно делать то, что вы хотите:

import re

def k(s):
    return [w.isdigit() and int(w) or w for w in re.split(r'(\d+)', s)]

files = ["u11-Phrase 099.wav", "u11-Phrase 1000.wav", "u11-Phrase 100.wav"]

print files
print sorted(files, key=k)

Это дает такой вывод:

['u11-Phrase 099.wav', 'u11-Phrase 1000.wav', 'u11-Phrase 100.wav']
['u11-Phrase 099.wav', 'u11-Phrase 100.wav', 'u11-Phrase 1000.wav']

Функция k разделит имена файлов на последовательности цифр и (что более важно) превратит эти последовательности в целые числа:

>>> k('u11-Phrase 099.wav')
['u', 11, '-Phrase ', 99, '.wav']

Затем мы используем тот факт, что Python знает, как сортировать списки - он сортирует списки, сравнивая каждый элемент один за другим. Конечным результатом является то, что

>>> k('u11-Phrase 99.wav') < k('u11-Phrase 100.wav')
True

тогда

>>> 'u11-Phrase 99.wav' < 'u11-Phrase 100.wav'
False

как вы уже узнали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...