Vérifiez si la chaîne se termine par l'une des chaînes d'une liste

220

Quelle est la manière pythonique d'écrire le code suivant?

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

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

J'ai un vague souvenir que la déclaration explicite de la forboucle peut être évitée et être écrite dans la ifcondition. Est-ce vrai?

TheMeaningfulEngineer
la source
2
Bien que cette question soit bien répondue, l'auteur a peut-être pensé à l'origine if any((file_name.endswith(ext) for ext in extensions)).
sapht

Réponses:

450

Bien que peu connu, str.endswith accepte également un tuple. Vous n'avez pas besoin de boucler.

>>> 'test.mp3'.endswith(('.mp3', '.avi'))
True
falsetru
la source
10
savez-vous pourquoi il n'accepte pas une liste mais fait un tuple? juste curieux
ilyail3
2
@falsetru Le lien dans la réponse ne répond pas explicitement à cette question. Il mentionne seulement qu'il peut accepter des tuples, mais pas pourquoi il ne peut pas accepter de listes. Puisqu'il s'agit de deux séquences, la seule différence que je peux potentiellement voir est que les listes sont mutables, tandis que les tuples sont immuables. Je peux me tromper, mais je ne vois aucune autre raison pour laquelle cela est explicitement indiqué.
KymikoLoco
4
Si vous voulez vérifier si une chaîne se termine par une lettre:import string; str.endswith(tuple(string.ascii_lowercase))
Alex Willison
3
juste une note, endswithaccepte le tuple uniquement pour python 2.5 et supérieur
Akash Singh
1
Je n'ai jamais su ça! C'est parfait!
fool4jesus
46

Utilisez simplement:

if file_name.endswith(tuple(extensions)):
Jon Clements
la source
Simple et efficace!
Ced
6

Prenez une extension dans le fichier et voyez si elle se trouve dans l'ensemble d'extensions:

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

Utilisation d'un ensemble car la complexité temporelle des recherches dans les ensembles est O (1) ( docs ).

alecxe
la source
8
Juste pour noter que vous mentionnez l'efficacité, pour des tuples assez courts, le .endswith()avec un tuple interne sera plus rapide qu'une recherche d'ensemble
Jon Clements
@JonClements Je pense que vous avez besoin d'un badge de commentaire spécial SO gold pour prendre des notes impressionnantes sur les réponses et les questions :)
alecxe
Non - je vais juste pour le badge "Stalking alecxe";)
Jon Clements
2
Notez également que dans la version 2.7 et plus récente, vous pouvez nous {'.mp3','.avi'}utiliser la syntaxe mathématique pour les ensembles, cela évite la conversion de type supplémentaire et peut être plus lisible en fonction de votre arrière-plan ('Bien que cela puisse causer de la confusion avec les dictionnaires et ne puisse pas être utilisé pour créer des espaces vides) ensembles).
Perkins
@JonClements un jour, je serai aussi sage que toi :)
alecxe
3

Il existe deux façons: les expressions régulières et les méthodes de chaîne (str).

Les méthodes de chaîne sont généralement plus rapides (~ 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 par boucle (moyenne ± écart standard de 7 pistes, 1000000 boucles chacune)

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

274 ns ± 4,22 ns par boucle (moyenne ± écart standard de 7 passages, 1000000 boucles chacun)

Igor A
la source
1

J'ai ceci:

def has_extension(filename, extension):

    ext = "." + extension
    if filename.endswith(ext):
        return True
    else:
        return False
Thomas Wouters
la source
1
Tu veux dire return filename.endswith(ext)? : P
Mr_and_Mrs_D
1

Je viens de tomber sur cela, tout en cherchant autre chose.

Je recommanderais d'aller avec les méthodes dans le ospaquet. C'est parce que vous pouvez le rendre plus général, en compensant tout cas étrange.

Vous pouvez faire quelque chose comme:

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.
Xxxo
la source
0

Une autre possibilité pourrait être d'utiliser la déclaration IN:

extensions = ['.mp3','.avi']
file_name  = 'test.mp3'
if "." in file_name and file_name[file_name.rindex("."):] in extensions:
    print(True)
NeverHopeless
la source
@ Rainald62, indexdevrait être rindexdans ce cas.
NeverHopeless
0

une autre façon qui peut renvoyer la liste des chaînes correspondantes est

sample = "alexis has the control"
matched_strings = filter(sample.endswith, ["trol", "ol", "troll"])
print matched_strings
['trol', 'ol']
Akash Singh
la source