Проверьте, заканчивается ли строка одной из строк из списка


220

Каков питонный способ написания следующего кода?

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

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

У меня есть смутное воспоминание, что явного объявления forцикла можно избежать и записать в ifусловии. Это правда?


2
Хотя на этот вопрос хорошо ответили, возможно, автор изначально задумался if any((file_name.endswith(ext) for ext in extensions)).
Сафт

Ответы:


450

Хотя str.endswith не очень широко известен, он также принимает кортеж. Вам не нужно зацикливаться.

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

10
Вы знаете, почему он не принимает список, но делает кортеж? просто любопытно
ilyail3

2
@falsetru Ссылка в ответе не дает четкого ответа на этот вопрос. В нем только упоминается, что он может принимать кортежи, но не почему он не может принимать списки. Поскольку они обе являются последовательностями, единственное различие, которое я могу видеть, состоит в том, что списки являются изменяемыми, а кортежи неизменными. Я могу ошибаться, но я не вижу никакой другой причины, по которой это прямо указано.
KymikoLoco

4
Если вы хотите проверить, заканчивается ли строка буквой:import string; str.endswith(tuple(string.ascii_lowercase))
Алекс Виллисон

3
только примечание, endswithпринимает кортеж только для Python 2.5 и выше
Акаш Сингх

1
Никогда этого не знал! Отлично!
fool4jesus


6

Возьмите расширение из файла и посмотрите, есть ли оно в наборе расширений:

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

Использование набора, потому что сложность времени для поиска в наборах составляет O (1) ( документы ).


8
Просто отметим, что, как вы упомянули, эффективность для довольно коротких кортежей .endswith()с интернированным кортежем будет быстрее, чем поиск по множеству
Джон Клементс

@JonClements Я думаю, вам нужен особый золотой значок комментария SO, чтобы делать отличные заметки об ответах и ​​вопросах :)
alecxe

Нет, я просто иду за значком "Подглядывающий алекс";)
Джон Клементс

2
Также обратите внимание, что в версии 2.7 и новее вы можете использовать математический синтаксис для множеств, {'.mp3','.avi'}это позволяет избежать дополнительного преобразования типов и может быть более читабельным в зависимости от вашего фона («Хотя это может вызвать путаницу со словарями и не может быть использовано для создания пустых»). наборы).
Перкинс

@JonClements когда-нибудь я стану таким же мудрым, как ты :)
alecxe

3

Есть два способа: регулярные выражения и строковые (str) методы.

Строковые методы обычно быстрее (~ 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 нс ± 1,83 нс на цикл (среднее ± стандартное отклонение из 7 циклов, 1000000 циклов в каждом)

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

274 нс ± 4,22 нс на цикл (среднее ± стандартное отклонение 7 циклов, 1000000 циклов в каждом)



1

Я только сталкивался с этим, ища что-то еще.

Я бы порекомендовал пойти с методами в osпакете. Это потому, что вы можете сделать это более общим, компенсируя любой странный случай.

Вы можете сделать что-то вроде:

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

Другой возможностью может быть использование оператора IN:

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

@ Rainald62, indexдолжно быть rindexв этом случае.
NeverHopeless

0

Другой способ, который может вернуть список совпадающих строк:

sample = "alexis has the control"
matched_strings = filter(sample.endswith, ["trol", "ol", "troll"])
print matched_strings
['trol', 'ol']
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.