2009-12-21 11 views
6

estoy corriendo Python 2.5 (R25: 51908 19 Sep 2006, 09:52:17) [32 bits MSC v.1310 (Intel)] en Win 32Python ordena "u11-Phrase 1000.wav" antes de "u11-Phrase 101.wav"; ¿Cómo puedo superar esto?

Cuando estoy pidiendo Python

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

Eso está bien. Cuando pregunto

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

Eso está bien, también. Pero cuando pido

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

Así que de acuerdo Python "100.wav U11-frase" viene antes de "1000.wav U11-frase" pero "101.wav U11-frase" viene después "U11-Frase 1000 .wav "! Y esto es problemático para mí porque estoy tratando de escribir un programa de cambio de nombre de archivo y este tipo de clasificación rompe la funcionalidad.

¿Qué puedo hacer para superar esto? ¿Debo escribir mi propia función de cmp y probar las cajas de borde o hay un atajo mucho más simple para darme el orden que quiero?

Por otro lado, si modifico las cadenas como

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

Sin embargo esas cadenas vienen de la lista de archivos del directorio como:

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

Así que prefiero no hacer quirúrgica operaciones en las cadenas después de que hayan sido creadas por glob. Y no, no quiero cambiar los nombres de archivo originales en esa carpeta, también.

¿Alguna pista?

Respuesta

16

Está buscando human sorting.

La razón 101.wav no es menor que 1000.wav es que las computadoras (no solo Python) ordenan las cadenas carácter por carácter, y la primera diferencia entre estas dos cadenas es donde la primera cadena tiene un '1' y la la segunda cuerda tiene un '0'. '1' no es menor que '0', por lo que las cuerdas se pueden comparar como lo ha visto.

Las personas naturalmente analizan esas cadenas en sus componentes e interpretan los números numéricamente, no léxicamente. El código que he vinculado arriba hará el mismo tipo de análisis.

+1

También llamado clasificación natural: http://www.codinghorror.com/blog/archives/001018.html –

+2

+1. Cool link, estaba a punto de responder la pregunta. No es necesario para esto ahora. – Boldewyn

9

Necesita construir una clave de clasificación adecuada para cada nombre de archivo. Algo como esto debería hacer lo que quiera:

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) 

Se da este resultado:

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

La función k dividirá aparte los nombres de archivo de secuencias de dígitos y (lo más importante) convertir esas secuencias en números enteros :

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

a continuación, utilizamos el hecho de que Python sabe cómo ordenar las listas --- ordena las listas mediante la comparación de cada elemento, uno por uno.El resultado final es que

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

mientras que

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

como ya has descubierto.

+0

Muchas gracias. Esto hace lo que espero y puedo usarlo como para archivos en ordenados (archivos, clave = k): imprimir archivo ... –

+0

Me pregunto si este orden de ordenamiento Natural/Humano alguna vez será parte de cualquier lib estándar en cualquier lenguaje de programación ... –

+0

@Emre, probablemente no, porque sería muy difícil encontrar algo que se aplique en general. Por ejemplo, es tan probable que la parte "u11" de la entrada se trate como una "u" y un entero 11, ya que debe tratarse como una simple cadena de 3 caracteres. Por lo general, esto es completamente contextual. Y en Python, al menos, escribir una función de clave de clasificación personalizada es muy fácil molestarse en hacer del único caso una rutina de biblioteca estándar. –