Sprawdź, czy łańcuch kończy się jednym z łańcuchów z listy


220

Jaki jest pythoniczny sposób pisania następującego kodu?

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

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

Mam niejasną pamięć, że formożna uniknąć jednoznacznej deklaracji pętli i zapisać ją pod ifwarunkiem. Czy to prawda?


2
Chociaż odpowiedź na to pytanie jest dobra, być może autor początkowo o tym myślał if any((file_name.endswith(ext) for ext in extensions)).
sapht

Odpowiedzi:


450

Chociaż nie jest to powszechnie znane, str.endswith akceptuje również krotkę. Nie musisz zapętlać.

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

10
Czy wiesz, dlaczego nie akceptuje listy, ale krotka? po prostu ciekawy
ilyail3,

2
@falsetru Link w odpowiedzi nie odpowiada wprost na to pytanie. Wspomina tylko, że może akceptować krotki, ale nie wyjaśnia, dlaczego nie akceptuje list. Ponieważ są to obie sekwencje, jedyną różnicą, którą potencjalnie widzę, jest to, że listy są zmienne, a krotki są niezmienne. Mogę się mylić, ale nie widzę żadnego innego powodu, dla którego zostało to wyraźnie stwierdzone.
KymikoLoco

4
Jeśli chcesz sprawdzić, czy ciąg znaków kończy się na literę:import string; str.endswith(tuple(string.ascii_lowercase))
Alex Willison

3
tylko uwaga, endswithakceptuje krotkę tylko dla Pythona 2.5 i nowszych
Akash Singh

1
Nigdy tego nie wiedziałem! To idealne!
fool4jesus


6

Weź rozszerzenie z pliku i sprawdź, czy znajduje się w zestawie rozszerzeń:

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

Używanie zestawu, ponieważ złożoność czasowa wyszukiwania w zestawach wynosi O (1) ( docs ).


8
Wystarczy wspomnieć o wydajności, w przypadku dość krótkich krotek .endswith()z krotką internowaną będzie szybsza niż wyszukiwanie zestawu
Jon Clements

@JonClements Wydaje mi się, że potrzebujesz specjalnej plakietki ze złotym komentarzem SO, aby robić niesamowite notatki na temat odpowiedzi i pytań :)
alecxe

Nie - wybieram się po odznakę „Stalking alecxe”;)
Jon Clements

2
Zauważ też, że w wersji 2.7 i nowszej możesz nam użyć składni matematycznej dla zestawów, {'.mp3','.avi'}pozwala to uniknąć dodatkowej konwersji typów i może być bardziej czytelna w zależności od tła („Może to powodować zamieszanie w słownikach i nie może być używane do tworzenia pustych zestawy).
Perkins

@JonClements pewnego dnia stanę się tak mądry jak ty :)
alecxe

3

Istnieją dwa sposoby: wyrażenia regularne i metody string (str).

Metody łańcuchowe są zwykle szybsze (~ 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 na pętlę (średnia ± odchylenie standardowe z 7 przebiegów, każdy 1000000 pętli)

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

274 ns ± 4,22 ns na pętlę (średnia ± odchylenie standardowe z 7 przebiegów, każda 1000000 pętli)


1

Mam to:

def has_extension(filename, extension):

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

1
Masz na myśli return filename.endswith(ext)? : P
Mr_and_Mrs_D

1

Właśnie się z tym spotkałem, szukając czegoś innego.

Poleciłbym skorzystać z metod zawartych w ospakiecie. Dzieje się tak, ponieważ możesz uczynić to bardziej ogólnym, kompensując każdy dziwny przypadek.

Możesz zrobić coś takiego:

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

Inną możliwością może być użycie instrukcji IN:

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

@ Rainald62, indexpowinien być rindexw takim przypadku.
NeverHopeless,

0

innym sposobem na zwrócenie listy pasujących ciągów jest

sample = "alexis has the control"
matched_strings = filter(sample.endswith, ["trol", "ol", "troll"])
print matched_strings
['trol', 'ol']
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.