6

Проверьте, содержатся ли несколько строк в другой строке

1

Вопрос: Как проверить, содержится ли хотя бы одна из строк в массиве в другой строке?

У меня есть массив строк, и я хочу проверить, присутствует ли хотя бы одна из этих строк в другой строке. Вот пример:

a = ['a', 'b', 'c']
s = "a123"
if a in s:
    print("Некоторые строки найдены в s")
else:
    print("Строки не найдены в s")

Как я могу заменить строку if a in s: на что-то, что даст правильный результат?

5 ответ(ов)

1

any() — это, безусловно, лучший способ, если вам нужно получить только True или False. Однако, если вас интересует, какие именно строки совпадают, вы можете воспользоваться несколькими подходами.

Если вам нужно найти первое совпадение (с False в качестве значения по умолчанию):

match = next((x for x in a if x in a_string), False)

Если вам нужно получить все совпадения (включая дубликаты):

matches = [x for x in a if x in a_string]

Если вы хотите получить все совпадения без дубликатов (не учитывая порядок):

matches = {x for x in a if x in a_string}

Если нужно получить все совпадения без дубликатов в правильном порядке:

matches = []
for x in a:
    if x in a_string and x not in matches:
        matches.append(x)
0

Вы можете использовать regex для добавления разнообразия в решение вашей задачи:

import re

if any(re.findall(r'a|b|c', str, re.IGNORECASE)):
    print('Возможные совпадения благодаря regex')
else:
    print('Совпадений нет')

Если ваш список слишком длинный, вы можете сделать это следующим образом:

any(re.findall(r'|'.join(a), str, re.IGNORECASE))

Это позволит вам эффективно проверять наличие совпадений, игнорируя регистр. Не забудьте заменить str на вашу переменную, содержащую строку, с которой вы работаете.

0

Чтобы перебрать элементы списка a и проверить, содержится ли каждый из них в строке a_string, вы можете использовать следующий код:

a = ['a', 'b', 'c']
a_string = "a123"
found_a_string = False

for item in a:    
    if item in a_string:
        found_a_string = True
        break  # Выход из цикла, если найдено совпадение

if found_a_string:
    print("found a match")
else:
    print("no match found")

В этом коде мы проходим по каждому элементу списка a и проверяем, содержится ли он в строке a_string. Если хотя бы один элемент найден в строке, переменная found_a_string устанавливается в True, и мы прерываем цикл. После завершения цикла мы проверяем значение found_a_string, чтобы определить, было ли найдено совпадение, и выводим соответствующее сообщение.

0

Вам нужно было реализовать это в контексте критичной к производительности среды, поэтому я провел бенчмарки всех возможных вариантов на Python 3.11. Вот результаты:

words = ['test', 'èk', 'user_me', '<markup>', '[^1]']

def find_words(words):
    for word in words:
        if "_" in word or "<" in word or ">" in word or "^" in word:
            pass

def find_words_2(words):
    for word in words:
        for elem in [">", "<", "_", "^"]:
            if elem in word:
                pass

def find_words_3(words):
    import re
    for word in words:
        if re.search(r"\_|\<|\>|\^", word):
            pass

def find_words_4(words):
    import re
    for word in words:
        if re.match(r"\S*(\_|\<|\>|\^)\S*", word):
            pass

def find_words_5(words):
    for word in words:
        if any(elem in word for elem in [">", "<", "_", "^"]):
            pass

def find_words_6(words):
    for word in words:
        if any(map(word.__contains__, [">", "<", "_", "^"])):
            pass

Результаты тестирования:

> %timeit find_words(words)
351 ns ± 6.24 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

> %timeit find_words_2(words)
689 ns ± 15.4 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

> %timeit find_words_3(words)
2.42 µs ± 43.9 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

> %timeit find_words_4(words)
2.75 µs ± 146 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

> %timeit find_words_5(words)
2.65 µs ± 176 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

> %timeit find_words_6(words)
1.64 µs ± 28.6 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
  1. Наиболее простой метод с использованием цепочки or (функция 1) показывает наилучшие результаты.
  2. Базовая итерация по каждому элементу (функция 2) как минимум на 50% быстрее, чем использование any(), при этом даже регэкспы работают быстрее, чем базовое any(), поэтому не понимаю, зачем он вообще нужен. К тому же синтаксис абсолютно алгоритмический, и любой программист сможет понять, что он делает, даже без опыта с Python.
  3. re.match() ищет только по шаблонам, начинающимся с начала строки (что может вызвать путаницу, если вы привыкли к регэкспам в PHP/Perl), поэтому чтобы он работал как в PHP/Perl, нужно использовать re.search() или модифицировать регэксп, что повлечет за собой потерю производительности.

Если список подстрок известен на этапе программирования, не стесняйтесь использовать неприглядный метод с цепочкой or. В противном случае лучше использовать простой цикл for по списку подстрок. any() и регулярные выражения — это потеря времени в этом контексте.

Для более практической задачи (определение, является ли файл изображением, исходя из его расширения в списке):

def is_image(word: str) -> bool:
    if any(ext in word for ext in [
        ".bmp", ".jpg", ".jpeg", ".jpe", ".jp2", ".j2c", ".j2k",
        ".jpc", ".jpf", ".jpx", ".png", ".ico", ".svg", ".webp",
        ".heif", ".heic", ".tif", ".tiff", ".hdr", ".exr", ".ppm",
        ".pfm", ".nef", ".rw2", ".cr2", ".cr3", ".crw", ".dng",
        ".raf", ".arw", ".srf", ".sr2", ".iiq", ".3fr", ".dcr",
        ".ari", ".pef", ".x3f", ".erf", ".raw", ".rwz"]):
        return True
    return False

IMAGE_PATTERN = re.compile(r"\.(bmp|jpg|jpeg|jpe|jp2|j2c|j2k|jpc|jpf|jpx|png|ico|svg|webp|heif|heic|tif|tiff|hdr|exr|ppm|pfm|nef|rw2|cr2|cr3|crw|dng|raf|arw|srf|sr2|iiq|3fr|dcr|ari|pef|x3f|erf|raw|rwz)")

Результаты bенчмарков:

> %timeit is_image("DSC_blablabla_001256.nef") # найдено
536 ns ± 18.3 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

> %timeit is_image("DSC_blablabla_001256.noop") # не найдено
923 ns ± 43.8 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

> %timeit IMAGE_PATTERN.search("DSC_blablabla_001256.nef")
221 ns ± 24.3 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

> %timeit IMAGE_PATTERN.search("DSC_blablabla_001256.noop") # не найдено
207 ns ± 4.3 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

> %timeit any(ext in "DSC_blablabla_001256.nef" for ext in extensions) # найдено
1.53 µs ± 30.1 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

> %timeit any(ext in "DSC_blablabla_001256.noop" for ext in extensions) # не найдено
2.2 µs ± 25.1 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

При большом количестве проверяемых элементов регэкспы действительно работают быстрее и более читаемы (в очередной раз…), чем цепочка or. any() все еще показывает худшие результаты.

Эмпирические тесты показывают, что порог производительности приходится на 9 элементов для проверки:

  • меньше 9 элементов — метод с цепочкой or быстрее,
  • больше 9 элементов — regex search() быстрее,
  • на ровно 9 элементах оба варианта работают примерно за 225 ns.
0

Ваш код на Python выполняет проверку, содержатся ли какие-либо элементы из списка a в строке str. Вот исправленный и более читаемый вариант с использованием Python 3:

a = ['a', 'b', 'c']
s = "a123"

a_match = [match for match in a if match in s]

if a_match:  # Проверяем, есть ли совпадения
    print("Некоторые строки найдены в str")
else:
    print("Строки не найдены в str")

Здесь я произвел следующие изменения:

  1. Переименовал переменную str в s, поскольку str является встроенной функцией в Python и не рекомендуется переопределять её.
  2. Упростил проверку на наличие совпадений, заменив if True in a_match на просто if a_match, так как если a_match непустой, это означает, что найдено хотя бы одно совпадение.
  3. Использовал функцию print() с круглой скобкой, чтобы соответствовать синтаксису Python 3.
Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь