부분 문자열을 모두 찾는 방법은 무엇입니까?


365

파이썬은 가지고 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]

11
무엇을 'ttt'.find_all('tt')반환 해야 합니까?
산티아고 알레

2
'0'을 반환해야합니다. 물론 완벽한 세상에는 'ttt'.rfind_all('tt')'1'을 반환해야합니다
nukl

답변:


523

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

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


안녕하세요, 관련된 [m.start() for m in re.finditer('test', 'test test test test')]우리는 얼마나 볼 수 있습니다, test또는 text? 훨씬 더 복잡해 집니까?
xpanta

7
일반적으로 docs.python.org/2/howto/regex.html 정규식을 보려고 합니다. 귀하의 질문에 대한 해결책은 다음과 같습니다 [m.start ()를 re.finditer에서 m ( '테 [SX] t', '텍스트 테스트 텍스트 테스트')에 대한]
Yotam 애 환자

1
이 방법을 사용하면 시간이 얼마나 복잡합니까?
Pranjal Mittal

1
@PranjalMittal. 상한 또는 하한? 최고, 최악 또는 평균 사례?
Mad Physicist

@marcog 하위 문자열에 괄호 나 다른 특수 문자가 포함되어 있으면 어떻게됩니까?
바나나

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

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


22
경기를 중복 얻으려면, 그것을 대체 할 충분합니다 start += len(sub)함께 start += 1.
Karl Knechtel

4
귀하의 이전 의견은 귀하의 답변에 포스트 스크립트이어야한다고 생각합니다.
tzot

1
"GATATATGCATATACTT"에서 "ATAT"코드는 SUBSTR 찾기 위해 작동하지 않습니다
인 Ashish 네기

2
내가 추가 한 의견을 참조하십시오. 이것이 겹치는 일치의 예입니다.
Karl Knechtel

4
의 동작과 일치하려면 대신 대신 re.findall추가 len(sub) or 1하는 것이 좋습니다 len(sub). 그렇지 않으면이 생성기는 빈 하위 문자열에서 종료되지 않습니다.
WGH

45

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

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

25

다시 말하지만 오래된 스레드이지만 여기에 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')]

3
이것은 아름답게 보인다!
fabio.sang

21

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

12
반복자에서 목록을 작성하는 이유는 프로세스 속도를 저하시킵니다.
pradyunsg 10

2
aString VS astring;)
NexD.

18

자, 같이 재귀합시다.

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]

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


방금 "파이썬에서 문자열 내부에 하위 문자열을 찾는 멋진 방법이 있습니까?" 공유해 주셔서 감사합니다 !!!
Geparada

3
이 코드에는 몇 가지 문제가 있습니다. 오픈 엔드 데이터를 조만간 작업하고 있기 때문에 RecursionError발생 횟수가 충분하면 부딪 칠 것 입니다. 다른 하나는 하나의 요소를 추가하기 위해 각 반복에서 생성하는 두 가지 폐기 목록입니다. 때로는 재귀 함수가 우아하고 명확 해 보이지만주의해서 사용해야합니다.
Ivan Nikolaev

11

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

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


GR8 솔루션은 .. 난 .. 분할 ()의 사용에 감명
샨의 Pathak를

9

이것은 오래된 스레드이지만 관심이있어서 솔루션을 공유하고 싶었습니다.

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

부분 문자열이 발견 된 위치 목록을 리턴해야합니다. 오류가 있거나 개선의 여지가 있다면 의견을 말하십시오.


6

이것은 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()))

5

이 스레드는 조금 낡았지만 나에게 효과적이었습니다.

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

당신은 시도 할 수 있습니다 :

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

다른 사람이 제공하는 솔루션은 사용 가능한 메소드 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 ( '이 답변이 도움이 되었습니까? 그런 다음 투표하십시오!', 'this')


2

이 함수는 문자열 내부의 모든 위치를 보지 않고 계산 리소스를 낭비하지 않습니다. 내 시도 :

def findAll(string,word):
    all_positions=[]
    next_pos=-1
    while True:
        next_pos=string.find(word,next_pos+1)
        if(next_pos<0):
            break
        all_positions.append(next_pos)
    return all_positions

그것을 사용하려면 다음과 같이 호출하십시오.

result=findAll('this word is a big word man how many words are there?','word')

1

문서에서 많은 양의 키워드를 찾을 때 플래시 텍스트를 사용 하십시오.

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
src = input() # we will find substring in this string
sub = input() # substring

res = []
pos = src.find(sub)
while pos != -1:
    res.append(pos)
    pos = src.find(sub, pos + 1)

1
이 코드는 OP 문제를 해결할 수 있지만 코드가 OP 문제를 해결하는 방법에 대한 설명을 포함하는 것이 가장 좋습니다. 이런 식으로, 미래 방문자는 귀하의 게시물에서 배우고 자신의 코드에 적용 할 수 있습니다. SO는 코딩 서비스가 아니라 지식을위한 리소스입니다. 또한 고품질의 완전한 답변이 상향 조정될 가능성이 높습니다. 이러한 기능은 모든 게시물이 자체적으로 포함되어야한다는 요구 사항과 함께 플랫폼으로서 SO의 강점 중 일부이며 포럼과 차별화됩니다. 추가 정보를 추가하거나 소스 문서로 설명을 보충하도록 편집 할 수 있습니다
SherylHohman

0

이것은 hackerrank의 비슷한 질문에 대한 해결책입니다. 나는 이것이 당신을 도울 수 있기를 바랍니다.

import re
a = input()
b = input()
if b not in a:
    print((-1,-1))
else:
    #create two list as
    start_indc = [m.start() for m in re.finditer('(?=' + b + ')', a)]
    for i in range(len(start_indc)):
        print((start_indc[i], start_indc[i]+len(b)-1))

산출:

aaadaa
aa
(0, 1)
(1, 2)
(4, 5)

-1

슬라이싱을 통해 가능한 모든 조합을 찾아 목록에 추가하고 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))

s="test test test test"f="test"코드를 인쇄 4영업 이익은 예상하지만[0,5,10,15]
barbsan

한 단어로 작성된 코드를 업데이트합니다
BONTHA SREEVIDHYA

-2

아래 코드를보십시오

#!/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)

-2

파이썬 방식은 다음과 같습니다.

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

3
1) 이것이 7 년 전에 답변 한 질문에 어떻게 도움이됩니까? 2) 이 방법을 사용 lambda하는 것은 Pythonic이 아니며 PEP8에 위배 됩니다. 3) 이것은 OP 상황에 대한 올바른 결과를 제공하지 않습니다
Wondercricket

"당신이 생각할 수있는 파이썬의 많은 기능으로 사용"파이썬은 의미하지 않는다
klutt

-2

당신은 쉽게 사용할 수 있습니다 :

string.count('test')!

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

건배!


이것이 답이되어야합니다
Maxwell Chandler

8
문자열 count () 메소드는 주어진 문자열에서 부분 문자열의 발생 횟수를 반환합니다. 그들의 위치가 아닙니다.
Astrid

5
이것은 모든 경우를 만족 시키지는 못합니다. s = 'banana', sub = 'ana'. Sub는이 상황에서 두 번 발생하지만 s.sub ( 'ana')를 수행하면 1을 반환합니다.
Joey Daniel Darko
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.