Поиск подстрок в строке
Есть ли в python встроенные инструкции, которые позволяют осуществлять поиск подстрок в строке?
Строка: Попробуй этих чудесных и спелых фруктов. Попробуешь?
Хочу найти: Поп
Должен получить: [0, 43]. Т.е. индексы всех вхождений в строку.
Ответы (4 шт):
Можно использовать регулярные выражения:
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
Как на счет такого варианта:
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]
Можно использовать алгоритм Кнута-Морриса-Пратта
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))]
Работать будет за линейное время от суммарных длин строк. Если вы хотите искать часто по одной строке, то кажется надо будет написать алгоритм Ахо-Корасика.