Controlla se la stringa termina con una delle stringhe di un elenco


220

Qual è il modo pitonico di scrivere il seguente codice?

extensions = ['.mp3','.avi']
file_name = 'test.mp3'

for extension in extensions:
    if file_name.endswith(extension):
        #do stuff

Ho un vago ricordo che la dichiarazione esplicita del forloop può essere evitata ed essere scritta nella ifcondizione. È vero?


2
Sebbene questa domanda abbia una buona risposta, forse l'autore ha inizialmente pensato if any((file_name.endswith(ext) for ext in extensions)).
Sapht

Risposte:


450

Sebbene non ampiamente conosciuto, str.endswith accetta anche una tupla. Non è necessario eseguire il loop.

>>> 'test.mp3'.endswith(('.mp3', '.avi'))
True

10
sai perché non accetta un elenco ma fa una tupla? solo curioso
ilyail3

2
@falsetru Il link nella risposta non risponde esplicitamente a questa domanda. Indica solo che può accettare le tuple, ma non il motivo per cui non può accettare elenchi. Poiché sono entrambe sequenze, l'unica differenza che posso potenzialmente vedere è che le liste sono mutabili, mentre le tuple sono immutabili. Potrei sbagliarmi, ma non vedo nessun altro motivo per cui ciò sia esplicitamente dichiarato.
KymikoLoco

4
Se vuoi verificare se una stringa termina con una lettera:import string; str.endswith(tuple(string.ascii_lowercase))
Alex Willison,

3
solo una nota, endswithaccetta la tupla solo per Python 2.5 e versioni successive
Akash Singh,

1
Non l'ho mai saputo! È perfetto!
fool4jesus


6

Prendi un'estensione dal file e vedi se è nel set di estensioni:

>>> import os
>>> extensions = set(['.mp3','.avi'])
>>> file_name = 'test.mp3'
>>> extension = os.path.splitext(file_name)[1]
>>> extension in extensions
True

L'uso di un set perché la complessità temporale per le ricerche negli insiemi è O (1) ( docs ).


8
Solo per notare che quando menzioni l'efficienza, per tuple abbastanza brevi, .endswith()con una tupla internata sarà più veloce di una ricerca impostata
Jon Clements

@JonClements Penso che tu abbia bisogno di uno speciale badge per i commenti SO gold per prendere appunti fantastici su risposte e domande :)
Alecxe

Nah - Sto solo andando per il badge "Stalking alecxe";)
Jon Clements

2
Nota anche che in 2.7 e versioni successive {'.mp3','.avi'}puoi usare la sintassi matematica per i set, evita la conversione del tipo extra e può essere più leggibile a seconda del tuo background ('Anche se può causare confusione con i dizionari e non può essere usato per creare vuoti imposta).
Perkins,

@JonClements un giorno diventerò saggio come te :)
alecxe

3

Esistono due modi: espressioni regolari e metodi string (str).

I metodi di stringa sono generalmente più veloci (~ 2x).

import re, timeit
p = re.compile('.*(.mp3|.avi)$', re.IGNORECASE)
file_name = 'test.mp3'
print(bool(t.match(file_name))
%timeit bool(t.match(file_name)

792 ns ± 1,83 ns per loop (media ± deviazione standard di 7 cicli, 1000000 loop ciascuno)

file_name = 'test.mp3'
extensions = ('.mp3','.avi')
print(file_name.lower().endswith(extensions))
%timeit file_name.lower().endswith(extensions)

274 ns ± 4,22 ns per loop (media ± deviazione standard di 7 cicli, 1000000 loop ciascuno)


1

Ho questo:

def has_extension(filename, extension):

    ext = "." + extension
    if filename.endswith(ext):
        return True
    else:
        return False

1
Intendi return filename.endswith(ext)? : P
Mr_and_Mrs_D

1

Mi sono appena imbattuto in questo, mentre cercavo qualcos'altro.

Consiglierei di seguire i metodi nel ospacchetto. Questo perché puoi renderlo più generale, compensando qualsiasi caso strano.

Puoi fare qualcosa del tipo:

import os

the_file = 'aaaa/bbbb/ccc.ddd'

extensions_list = ['ddd', 'eee', 'fff']

if os.path.splitext(the_file)[-1] in extensions_list:
    # Do your thing.

0

Un'altra possibilità potrebbe essere quella di utilizzare l'istruzione IN:

extensions = ['.mp3','.avi']
file_name  = 'test.mp3'
if "." in file_name and file_name[file_name.rindex("."):] in extensions:
    print(True)

@ Rainald62, indexdovrebbe essere rindexin quel caso.
NeverHopeless,

0

un altro modo che può restituire l'elenco delle stringhe corrispondenti è

sample = "alexis has the control"
matched_strings = filter(sample.endswith, ["trol", "ol", "troll"])
print matched_strings
['trol', 'ol']
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.