it-roy-ru.com

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

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

Интересно, может быть есть что-то вроде string.find_all(), которая может возвращать все найденные индексы (не только сначала с начала или сначала с конца)?

Например:

string = "test test test test"

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

#that's the goal
print string.find_all('test') # [0,5,10,15]
273
nukl

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

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 возвращает generator , так что вы можете изменить [] в приведенном выше примере на (), чтобы получить генератор вместо списка, который будет более эффективен, если вы повторяете результаты только один раз.

421
marcog
>>> 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]

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

85
Karl Knechtel

Вот (очень неэффективный) способ получить все (то есть даже перекрывающиеся) совпадения:

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

Вы можете использовать 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)]
19
Chinmay Kanchi

Опять же, старый поток, но вот мое решение, использующее генератор и обычный 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')]
18
AkiRoss

Давай, давай вернёмся вместе.

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]

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

17
Cody Piersall

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

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
jstaab

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

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

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

8
Thurines

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

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)
5
Andrew H

Это делает трюк для меня, используя 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()))
3
Bruno Vermeulen

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

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

0
5
10
15
2
Harsha Biyani

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

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

def find_all(string,substring):
    """
    Function: Returning all the index of substring in a string
    Arguments: String and the search string
    Return:Returning a list
    """
    length = len(substring)
    c=0
    indexes = []
    while c < len(string):
        if string[c:c+length] == substring:
            indexes.append(c)
        c=c+1
    return indexes

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

class newstr(str):
def find_all(string,substring):
    """
    Function: Returning all the index of substring in a string
    Arguments: String and the search string
    Return:Returning a list
    """
    length = len(substring)
    c=0
    indexes = []
    while c < len(string):
        if string[c:c+length] == substring:
            indexes.append(c)
        c=c+1
    return indexes

Вызов метода

newstr.find_all («Считаете ли вы этот ответ полезным? тогда upvote this!», «this»)

2
naveen raja

Вы можете легко использовать:

string.count('test')!

https://www.programiz.com/python-programming/methods/string/count

Ура!

0
RaySaraiva

При поиске большого количества ключевых слов в документе используйте 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 работает быстрее, чем регулярное выражение для большого списка поисковых слов.

0
Uri Goren