[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]



답변

원하는 것을 수행하는 간단한 내장 문자열 함수는 없지만 더 강력한 정규 표현식을 사용할 수 있습니다 .

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생성기를 반환 하므로 결과 대신 한 번만 반복하는 경우보다 효율적인 목록 대신 생성기를 얻 []도록 위의를 변경할 수 있습니다 ().


답변

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

임시 문자열이나 정규식이 필요하지 않습니다.


답변

모든 (즉, 겹치는) 일치 를 얻는 (매우 비효율적 인) 방법은 다음과 같습니다.

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


답변

다시 말하지만 오래된 스레드이지만 여기에 generator 와 plain을 사용하는 솔루션이 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')]


답변

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)]


답변

자, 같이 재귀합시다.

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]

이런 식으로 정규 표현식이 필요하지 않습니다.


답변

단일 문자를 찾고 있다면 다음과 같이 작동합니다.

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) 굉장히 성능이 좋지 않다는 것이다.