Поиск подстрок в строке

Есть ли в python встроенные инструкции, которые позволяют осуществлять поиск подстрок в строке?

Строка: Попробуй этих чудесных и спелых фруктов. Попробуешь?

Хочу найти: Поп

Должен получить: [0, 43]. Т.е. индексы всех вхождений в строку.


Ответы (4 шт):

Автор решения: nightflash

Можно использовать регулярные выражения:

import re
print([m.start() for m in re.finditer('test', 'test test test test')])
#[0, 5, 10, 15]
→ Ссылка
Автор решения: Евгений

Вы можете собирать список вхождений строки, каждый раз обрезая уже учтённое вхождение

def findall(s, substr):
  def searching(s, substr):
    offset = 0
    while s.find(substr) != -1:
      yield s.find(substr) + offset
      offset += len(substr) + s.find(substr)
      s = s[s.find(substr) + len(substr):]
  return list(searching(s,substr))

print(findall('Попробуй этих чудесных и спелых фруктов. Попробуешь?', 'Поп'))

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

def findall(s, substr):
  def searching(s, substr):
    while s.rfind(substr) != -1:
      yield s.rfind(substr)
      s = s[:s.rfind(substr)]
  return list(reversed(list(searching(s,substr))))

print(findall('Попробуй этих чудесных и спелых фруктов. Попробуешь?', 'Поп'))

Результат работы обеих вариантов функций:

[0, 41] # да, второе вхождение подстроки находится именно на 41 позиции, а не на 43
→ Ссылка
Автор решения: MaxU

Как на счет такого варианта:

def find_all(s, sub):
    res = []
    cur_pos = 0
    for x in s.split(sub)[:-1]:
        cur_pos += len(x)
        res.append(cur_pos)
        cur_pos += len(sub)
    return res

In [187]: find_all("Попробуй этих чудесных и спелых фруктов. Попробуешь?", "Поп")
Out[187]: [0, 41]
→ Ссылка
Автор решения: LIshy2

Можно использовать алгоритм Кнута-Морриса-Пратта

def find_all(source, sub):
    def prefix_func(s):
        pr = [0] * (len(s))
        for i in range(1, len(s)):
            k = pr[i - 1]
            while k > 0 and s[k] != s[i]:
                k = pr[k - 1]
            if s[k] == s[i]:
                k = k + 1
            pr[i] = k
        return pr

    result = prefix_func(sub + "$" + source)  # вместо доллара может быть любой другой не встречаюшийся символ
    return [index for index, element in enumerate(result) if (element >= len(sub))]

Работать будет за линейное время от суммарных длин строк. Если вы хотите искать часто по одной строке, то кажется надо будет написать алгоритм Ахо-Корасика.

→ Ссылка