Compruebe si la cadena termina con una de las cadenas de una lista


220

¿Cuál es la forma pitónica de escribir el siguiente código?

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

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

Tengo un vago recuerdo de que la declaración explícita del forbucle puede evitarse y escribirse en la ifcondición. ¿Es esto cierto?


2
Aunque esta pregunta está bien respondida, tal vez el autor pensó originalmente if any((file_name.endswith(ext) for ext in extensions)).
Sapht

Respuestas:


450

Aunque no es ampliamente conocido, str.endswith también acepta una tupla. No necesitas hacer un bucle.

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

10
¿Sabes por qué no acepta una lista pero sí una tupla? curioso
ilyail3

2
@falsetru El enlace en la respuesta no responde explícitamente a esa pregunta. Solo menciona que puede aceptar tuplas, pero no por qué no puede aceptar listas. Dado que ambas son secuencias, la única diferencia que puedo ver potencialmente es que las listas son mutables, mientras que las tuplas son inmutables. Puedo estar equivocado, pero no puedo ver ninguna otra razón por la cual se afirma explícitamente.
KymikoLoco

44
Si desea verificar si una cadena termina con una letra:import string; str.endswith(tuple(string.ascii_lowercase))
Alex Willison

3
solo una nota, endswithacepta tupla solo para python 2.5 y superior
Akash Singh

1
¡Nunca supe esto! ¡Eso es perfecto!
fool4jesus


6

Tome una extensión del archivo y vea si está en el conjunto de extensiones:

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

Usar un conjunto porque la complejidad temporal para las búsquedas en conjuntos es O (1) ( docs ).


8
Solo para notar como mencionas la eficiencia, para tuplas bastante cortas, .endswith()con una tupla interna será más rápido que una búsqueda establecida
Jon Clements

@ JonClements Creo que necesitas una insignia especial de comentario SO gold para tomar notas increíbles sobre respuestas y preguntas :)
alecxe

No, solo voy por la insignia "Stalking alecxe";)
Jon Clements

2
Tenga en cuenta también que en 2.7 y versiones posteriores, {'.mp3','.avi'}puede usar la sintaxis matemática para conjuntos, evita la conversión de tipo adicional y puede ser más legible dependiendo de su fondo ('Aunque puede causar confusión con los diccionarios y no puede usarse para crear vacíos conjuntos).
Perkins

@JonClements algún día voy a ser tan sabio como tú :)
alecxe

3

Hay dos formas: expresiones regulares y métodos de cadena (str).

Los métodos de cadena suelen ser más rápidos (~ 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 por bucle (media ± desviación estándar de 7 corridas, 1000000 bucles cada una)

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

274 ns ± 4.22 ns por bucle (media ± desviación estándar de 7 corridas, 1000000 bucles cada una)


1

Tengo esto:

def has_extension(filename, extension):

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

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

1

Acabo de encontrar esto, mientras buscaba algo más.

Recomendaría ir con los métodos en el ospaquete. Esto se debe a que puede hacerlo más general, compensando cualquier caso extraño.

Puedes hacer algo como:

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

Otra posibilidad podría ser hacer uso de la declaración IN:

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

@ Rainald62, indexdebería estar rindexen ese caso.
NeverHopeless

0

Otra forma de devolver la lista de cadenas coincidentes es

sample = "alexis has the control"
matched_strings = filter(sample.endswith, ["trol", "ol", "troll"])
print matched_strings
['trol', 'ol']
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.