Как найти все вхождения подстроки?

В Python есть string.find() и string.rfind() для получения индекса подстроки в строке.

Мне интересно, есть ли что-то вроде string.find_all() которое может вернуть все найденные индексы (не только первый с начала или первый с конца).

Например:

string = "test test test test"

print string.find('test') # 0
print string.rfind('test') # 15

#this is the goal
print string.find_all('test') # [0,5,10,15]

Ответ 1

Нет простой встроенной строковой функции, которая делает то, что вы ищете, но вы можете использовать более мощные регулярные выражения:

import re
[m.start() for m in re.finditer('test', 'test test test test')]
#[0, 5, 10, 15]

Если вы хотите найти совпадающие совпадения, lookahead сделает это:

[m.start() for m in re.finditer('(?=tt)', 'ttt')]
#[0, 1]

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

search = 'tt'
[m.start() for m in re.finditer('(?=%s)(?!.{1,%d}%s)' % (search, len(search)-1, search), 'ttt')]
#[1]

re.finditer возвращает генератор, поэтому вы можете изменить [] в приведенном выше re.finditer на () чтобы получить генератор вместо списка, который будет более эффективен, если вы будете только повторять результаты один раз.

Ответ 2

>>> help(str.find)
Help on method_descriptor:

find(...)
    S.find(sub [,start [,end]]) -> int

Таким образом, мы можем сами его построить:

def find_all(a_str, sub):
    start = 0
    while True:
        start = a_str.find(sub, start)
        if start == -1: return
        yield start
        start += len(sub) # use start += 1 to find overlapping matches

list(find_all('spam spam spam spam', 'spam')) # [0, 5, 10, 15]

Никаких временных строк или регулярных выражений не требуется.

Ответ 3

Здесь (очень неэффективный) способ получить все (т.е. даже совпадение):

>>> string = "test test test test"
>>> [i for i in range(len(string)) if string.startswith('test', i)]
[0, 5, 10, 15]

Ответ 4

Вы можете использовать re.finditer() для совпадающих совпадений.

>>> import re
>>> aString = 'this is a string where the substring "is" is repeated several times'
>>> print [(a.start(), a.end()) for a in list(re.finditer('is', aString))]
[(2, 4), (5, 7), (38, 40), (42, 44)]

но не будет работать:

In [1]: aString="ababa"

In [2]: print [(a.start(), a.end()) for a in list(re.finditer('aba', aString))]
Output: [(0, 3)]

Ответ 5

Опять старый поток, но здесь мое решение использует генератор и обычный str.find.

def findall(p, s):
    '''Yields all the positions of
    the pattern p in the string s.'''
    i = s.find(p)
    while i != -1:
        yield i
        i = s.find(p, i+1)

Пример

x = 'banananassantana'
[(i, x[i:i+2]) for i in findall('na', x)]

возвращает

[(2, 'na'), (4, 'na'), (6, 'na'), (14, 'na')]

Ответ 6

Приходите, давайте возместим вместе.

def locations_of_substring(string, substring):
    """Return a list of locations of a substring."""

    substring_length = len(substring)    
    def recurse(locations_found, start):
        location = string.find(substring, start)
        if location != -1:
            return recurse(locations_found + [location], location+substring_length)
        else:
            return locations_found

    return recurse([], 0)

print(locations_of_substring('this is a test for finding this and this', 'this'))
# prints [0, 27, 36]

Нет необходимости в регулярных выражениях таким образом.

Ответ 7

Если вы ищете только один символ, это будет работать:

string = "dooobiedoobiedoobie"
match = 'o'
reduce(lambda count, char: count + 1 if char == match else count, string, 0)
# produces 7

Кроме того,

string = "test test test test"
match = "test"
len(string.split(match)) - 1
# produces 4

Моя догадка заключается в том, что ни один из них (особенно # 2) не ужасен.

Ответ 8

Это старый поток, но я заинтересовался и хотел поделиться своим решением.

def find_all(a_string, sub):
    result = []
    k = 0
    while k < len(a_string):
        k = a_string.find(sub, k)
        if k == -1:
            return result
        else:
            result.append(k)
            k += 1 #change to k += len(sub) to not search overlapping results
    return result

Он должен вернуть список позиций, в которых была найдена подстрока. Прокомментируйте, если вы видите ошибку или комнату для улучшения.

Ответ 9

Этот поток немного стар, но это сработало для меня:

numberString = "onetwothreefourfivesixseveneightninefiveten"
testString = "five"

marker = 0
while marker < len(numberString):
    try:
        print(numberString.index("five",marker))
        marker = numberString.index("five", marker) + 1
    except ValueError:
        print("String not found")
        marker = len(numberString)

Ответ 10

Вы можете попробовать:

>>> string = "test test test test"
>>> for index,value in enumerate(string):
    if string[index:index+(len("test"))] == "test":
        print index

0
5
10
15

Ответ 11

Это делает трюк для меня, используя re.finditer

import re

text = 'This is sample text to test if this pythonic '\
       'program can serve as an indexing platform for '\
       'finding words in a paragraph. It can give '\
       'values as to where the word is located with the '\
       'different examples as stated'

#  find all occurances of the word 'as' in the above text

find_the_word = re.finditer('as', text)

for match in find_the_word:
    print('start {}, end {}, search string \'{}\''.
          format(match.start(), match.end(), match.group()))

Ответ 12

Независимо от решений, предоставляемых другими, полностью зависит от доступного метода find() или любых доступных методов.

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

  def find_all (строка, подстрока):    ""   Функция: Возврат всего индекса подстроки в строку   Аргументы: Строка и строка поиска   Возврат: возврат списка    ""   length = len (подстрока)   с = 0   indexes = []   в то время как c < Len (строка):       if string [c: c + length] == substring:           indexes.append(с)       с = с + 1   индексы возврата
Код>

Вы также можете наследовать класс str новому классу и можете использовать эту функцию ниже.

  class newstr (str):
def find_all (строка, подстрока):    ""   Функция: Возврат всего индекса подстроки в строку   Аргументы: Строка и строка поиска   Возврат: возврат списка    ""   length = len (подстрока)   с = 0   indexes = []   в то время как c < Len (строка):       if string [c: c + length] == substring:           indexes.append(с)       с = с + 1   индексы возврата
Код>

Вызов метода

newstr.find_all ( "Вы находите этот ответ полезным?" это!", 'this')

Ответ 13

При поиске большого количества ключевых слов в документе используйте flashtext

from flashtext import KeywordProcessor
words = ['test', 'exam', 'quiz']
txt = 'this is a test'
kwp = KeywordProcessor()
kwp.add_keywords_from_list(words)
result = kwp.extract_keywords(txt, span_info=True)

Flashtext работает быстрее, чем регулярное выражение в большом списке поисковых слов.

Ответ 15

Разрезая, мы находим все возможные комбинации и добавляем их в список и определяем, сколько раз это происходит, используя функцию count

s=input()
n=len(s)
l=[]
f=input()
print(s[0])
for i in range(0,n):
    for j in range(1,n+1):
        l.append(s[i:j])
if f in l:
    print(l.count(f))

Ответ 16

Питонический путь:

mystring = 'Hello World, this should work!'
find_all = lambda c,s: [x for x in range(c.find(s), len(c)) if c[x] == s]

# s represents the search string
# c represents the character string

find_all(mystring,'o')    # will return all positions of 'o'

[4, 7, 20, 26] 
>>> 

Ответ 17

посмотрите ниже код

#!/usr/bin/env python
# coding:utf-8
'''黄哥Python'''


def get_substring_indices(text, s):
    result = [i for i in range(len(text)) if text.startswith(s, i)]
    return result


if __name__ == '__main__':
    text = "How much wood would a wood chuck chuck if a wood chuck could chuck wood?"
    s = 'wood'
    print get_substring_indices(text, s)