2009-12-21 10 views
6

Io corro Python 2.5 (R25: 51908, 19 Settembre, 2006, 09:52:17) [MSC v.1310 32 bit (Intel)] sulla vittoria 32Python ordina "u11-Phrase 1000.wav" prima di "u11-Phrase 101.wav"; come posso superare questo?

Quando mi sto chiedendo Python

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

Va bene. Quando chiedo

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

Anche questo va bene. Ma quando chiedo

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

Quindi, secondo Python "U11-Frase 100.wav" viene prima "U11-Frase 1000.wav", ma "U11-Frase 101.wav" viene dopo "U11-Frase 1000 wav "! E questo per me è problematico perché sto provando a scrivere un programma di ridenominazione di file e questo tipo di ordinamento interrompe la funzionalità.

Cosa posso fare per superare questo? Devo scrivere la mia funzione cmp e testare i casi limite o c'è una scorciatoia molto più semplice per darmi l'ordine che voglio?

D'altra parte se modifico le corde, come

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

Tuttavia quelle stringhe provengono da l'elenco dei file della directory, ad esempio:

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

Quindi preferirei non lo faccio chirurgica operazioni sulle stringhe dopo che sono state create da glob. E no, non voglio cambiare i nomi dei file originali anche in quella cartella.

Eventuali suggerimenti?

risposta

16

Stai cercando human sorting.

Il motivo 101.wav non è inferiore a 1000.wav è che i computer (non solo Python) ordinano le stringhe carattere per carattere, e la prima differenza tra queste due stringhe è dove la prima stringa ha un '1' e il la seconda stringa ha uno '0'. '1' non è inferiore a '0', quindi le stringhe confrontano come hai visto.

Le persone analizzano naturalmente queste stringhe nei loro componenti e interpretano numericamente i numeri, non in modo lessicale. Il codice che ho collegato sopra farà lo stesso tipo di analisi.

+1

Chiamato anche ordinamento naturale: http://www.codinghorror.com/blog/archives/001018.html –

+2

+1. Cool link, stavo per rispondere alla domanda. Non c'è bisogno di questo ora. – Boldewyn

9

È necessario creare una chiave di ordinamento corretta per ciascun nome file. Qualcosa del genere dovrebbe fare quello che vuoi:

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) 

Dà questa uscita:

['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 funzione k dividerà a parte i nomi dei file su sequenze di cifre e (soprattutto) girare quelle sequenze in numeri interi :

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

Utilizziamo poi il fatto che Python sa come ordinare le liste --- è sorta negli elenchi confrontando ogni elemento uno per uno.Il risultato finale è che

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

mentre

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

come hai già scoperto.

+0

Grazie mille. Questo è quello che mi aspetto e posso usarlo come per file in ordine (file, chiave = k): file di stampa ... –

+0

Mi chiedo se questo ordinamento di tipo Naturale/Umano sarà mai parte di qualsiasi lib standard in qualsiasi linguaggio di programmazione ... –

+0

@Emre, probabilmente no, perché sarebbe molto difficile trovare qualcosa che si applica in generale. Ad esempio, è altrettanto probabile che la parte "u11" dell'input debba essere trattata come una "u" e un intero 11 in quanto dovrebbe essere trattata come una semplice stringa di 3 caratteri. Di solito questo è interamente sensibile al contesto. E in Python, almeno, scrivere una funzione di chiave di ordinamento personalizzata è troppo facile da disturbare facendo solo un caso una routine di libreria standard. –