Bagaimana menemukan semua kemunculan substring?

365

Python memiliki string.find()dan string.rfind()untuk mendapatkan indeks substring dalam sebuah string.

Saya bertanya-tanya apakah ada sesuatu string.find_all()yang dapat mengembalikan semua indeks yang ditemukan (tidak hanya yang pertama dari awal atau yang pertama dari akhir).

Sebagai contoh:

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]
nukl
sumber
11
apa yang harus 'ttt'.find_all('tt')kembali?
Santiago Alessandri
2
seharusnya mengembalikan '0'. Tentu saja, di dunia yang sempurna juga harus ada 'ttt'.rfind_all('tt'), yang seharusnya mengembalikan '1'
nukl
2
Sepertinya duplikat dari stackoverflow.com/questions/3873361/…
nu everest

Jawaban:

523

Tidak ada fungsi string bawaan yang melakukan apa yang Anda cari, tetapi Anda bisa menggunakan ekspresi reguler yang lebih kuat :

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

Jika Anda ingin menemukan kecocokan yang tumpang tindih, lookahead akan melakukan itu:

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

Jika Anda ingin menemukan yang terbalik-semua tanpa tumpang tindih, Anda dapat menggabungkan tampilan positif dan negatif ke dalam ekspresi seperti ini:

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

re.finditermengembalikan generator , sehingga Anda dapat mengubah []di atas untuk ()mendapatkan generator, bukan daftar yang akan lebih efisien jika Anda hanya mengulangi hasilnya sekali saja.

moinudin
sumber
hai, mengenai ini [m.start() for m in re.finditer('test', 'test test test test')], bagaimana kita bisa mencari testatau text? Apakah ini menjadi jauh lebih rumit?
xpanta
7
Anda ingin melihat ekspresi reguler secara umum: docs.python.org/2/howto/regex.html . Solusi untuk pertanyaan Anda adalah: [m. mulai () untuk m di re.finditer ('te [sx] t', 'tes teks tes teks')]
Yotam Vaknin
1
Apa kompleksitas waktu menggunakan metode ini?
Pranjal Mittal
1
@PranjalMittal. Batas atas atau batas bawah? Kasus terbaik, terburuk atau rata-rata?
Fisikawan Gila
@marcog bagaimana jika substring berisi tanda kurung atau karakter khusus lainnya?
Bananach
109
>>> help(str.find)
Help on method_descriptor:

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

Dengan demikian, kita dapat membangunnya sendiri:

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]

Tidak diperlukan string atau regex sementara.

Karl Knechtel
sumber
22
Untuk mendapatkan tumpang tindih pertandingan, itu harus cukup untuk mengganti start += len(sub)dengan start += 1.
Karl Knechtel
4
Saya yakin komentar Anda sebelumnya harus berupa nota tambahan dalam jawaban Anda.
tzot
1
Kode Anda tidak berfungsi untuk menemukan substr: "ATAT" di "GATATATGCATATACTT"
Ashish Negi
2
Lihat komentar yang saya buat sebagai tambahan. Itu adalah contoh pertandingan yang tumpang tindih.
Karl Knechtel
4
Untuk mencocokkan perilaku re.findall, saya sarankan menambahkan len(sub) or 1bukan len(sub), jika tidak generator ini tidak akan pernah berakhir pada substring kosong.
WGH
45

Inilah cara (yang sangat tidak efisien) untuk mendapatkan semua kecocokan (yaitu, bahkan tumpang tindih):

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

Sekali lagi, utas lama, tapi inilah solusi saya menggunakan generator dan polos 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)

Contoh

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

kembali

[(2, 'na'), (4, 'na'), (6, 'na'), (14, 'na')]
AkiRoss
sumber
3
ini terlihat indah!
fabio.sang
21

Anda dapat menggunakan re.finditer()untuk pertandingan yang tidak tumpang tindih.

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

tetapi tidak akan bekerja untuk:

In [1]: aString="ababa"

In [2]: print [(a.start(), a.end()) for a in list(re.finditer('aba', aString))]
Output: [(0, 3)]
Chinmay Kanchi
sumber
12
Mengapa membuat daftar dari iterator, itu hanya memperlambat proses.
pradyunsg
2
aString VS astring;)
NexD.
18

Ayo, mari kita kembali bersama.

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]

Tidak perlu untuk ekspresi reguler seperti ini.

Cody Piersall
sumber
Saya baru saja mulai bertanya-tanya "apakah ada cara mewah untuk menemukan substring di dalam string dengan python" ... dan kemudian setelah 5 menit googling saya menemukan kode Anda. Terima kasih telah berbagi!!!
Geparada
3
Kode ini memiliki beberapa masalah. Karena ini bekerja pada data terbuka cepat atau lambat Anda akan bertemu RecursionErrorjika ada cukup banyak kejadian. Yang lain adalah dua daftar membuang yang dibuat pada setiap iterasi hanya untuk menambahkan satu elemen, yang sangat suboptimal untuk fungsi pencarian string, yang mungkin bisa disebut berkali-kali. Meskipun kadang-kadang fungsi rekursif tampak elegan dan jelas, mereka harus diambil dengan hati-hati.
Ivan Nikolaev
11

Jika Anda hanya mencari satu karakter, ini akan berhasil:

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

Juga,

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

Firasat saya adalah bahwa tidak satu pun dari ini (terutama # 2) yang sangat performant.

jstaab
sumber
solusi gr8 .. saya terkesan dengan penggunaan .. split ()
shantanu pathak
9

ini adalah utas lama tetapi saya tertarik dan ingin membagikan solusi saya.

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

Ini harus mengembalikan daftar posisi tempat substring ditemukan. Berikan komentar jika Anda melihat kesalahan atau ruang untuk perbaikan.

Thurines
sumber
6

Ini melakukan trik untuk saya menggunakan 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()))
Bruno Vermeulen
sumber
5

Utas ini agak lama tetapi ini berhasil untuk saya:

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

Anda dapat mencoba :

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

0
5
10
15
Harsha Biyani
sumber
2

Apa pun solusi yang disediakan oleh orang lain sepenuhnya didasarkan pada metode find yang tersedia () atau metode apa pun yang tersedia.

Apa algoritma dasar dasar untuk menemukan semua kemunculan substring dalam string?

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

Anda juga dapat mewarisi kelas str ke kelas baru dan dapat menggunakan fungsi ini di bawah.

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

Memanggil metode

newstr.find_all ('Apakah Anda menganggap jawaban ini bermanfaat? lalu balaskan ini!', 'ini')

naveen raja
sumber
2

Fungsi ini tidak melihat semua posisi di dalam string, tidak membuang sumber daya komputasi. Usaha saya:

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

untuk menggunakannya menyebutnya seperti ini:

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

Saat mencari sejumlah besar kata kunci dalam dokumen, gunakan 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 berjalan lebih cepat daripada regex pada daftar kata pencarian yang besar.

Uri Goren
sumber
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)
mascai
sumber
1
Meskipun kode ini dapat menyelesaikan masalah OP, yang terbaik adalah memasukkan penjelasan tentang bagaimana kode Anda mengatasi masalah OP. Dengan cara ini, pengunjung masa depan dapat belajar dari posting Anda, dan menerapkannya pada kode mereka sendiri. SO bukan layanan pengkodean, tetapi sumber daya untuk pengetahuan. Juga, kualitas tinggi, jawaban lengkap lebih cenderung terunggulkan. Fitur-fitur ini, bersama dengan persyaratan bahwa semua posting mandiri, adalah beberapa kekuatan SO sebagai platform, yang membedakannya dari forum. Anda dapat mengedit untuk menambahkan info tambahan & / atau untuk melengkapi penjelasan Anda dengan dokumentasi sumber
SherylHohman
0

Ini adalah solusi dari pertanyaan serupa dari hackerrank. Saya harap ini bisa membantu Anda.

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

Keluaran:

aaadaa
aa
(0, 1)
(1, 2)
(4, 5)
Ruman Khan
sumber
-1

Dengan mengiris kami menemukan semua kombinasi yang mungkin dan menambahkannya dalam daftar dan menemukan berapa kali itu terjadi menggunakan countfungsi

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))
BONTHA SREEVIDHYA
sumber
Kapan s="test test test test"dan f="test"kode Anda dicetak 4, tetapi OP diharapkan[0,5,10,15]
barbsan
Telah menulis untuk satu kata akan memperbarui kode
BONTHA SREEVIDHYA
-2

silakan lihat kode di bawah ini

#!/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)
黄 哥 Python 培训
sumber
-2

Cara pythonic adalah:

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] 
>>> 
Harvey
sumber
3
1) Bagaimana hal ini membantu pertanyaan yang dijawab 7 tahun yang lalu? 2) Menggunakan lambdacara ini bukan Pythonic dan bertentangan dengan PEP8 . 3) Ini tidak memberikan output yang benar untuk situasi OP
Wondercricket
Pythonic tidak berarti "Gunakan sebanyak mungkin fitur python seperti yang Anda pikirkan"
klutt
-2

Anda dapat dengan mudah menggunakan:

string.count('test')!

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

Bersulang!

RaySaraiva
sumber
ini seharusnya jawabannya
Maxwell Chandler
8
Metode string count () mengembalikan jumlah kemunculan substring dalam string yang diberikan. Bukan lokasi mereka.
Astrid
5
ini tidak memenuhi semua kasus, s = 'pisang', sub = 'ana'. Sub terjadi dalam situasi ini dua kali tetapi melakukan s.sub ('ana') akan mengembalikan 1
Joey daniel darko