Найти все вхождения подстроки в 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]
32 ответа
Нет простой встроенной строковой функции, которая делает то, что вы ищете, но вы могли бы использовать более мощные регулярные выражения:
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]
Опять старая ветка, но вот мое решение с использованием генератора и простого 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) не очень эффективен.
Это старая тема, но я заинтересовался и хотел поделиться своим решением.
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
Должен возвращать список позиций, где найдена подстрока. Пожалуйста, прокомментируйте, если вы видите ошибку или место для улучшения.
Это делает трюк для меня, используя 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()))
Ты можешь попробовать :
import re
str1 = "This dress looks good; you have good taste in clothes."
substr = "good"
result = [_.start() for _ in re.finditer(substr, str1)]
# result = [17, 32]
Ты можешь попробовать:
>>> string = "test test test test"
>>> for index,value in enumerate(string):
if string[index:index+(len("test"))] == "test":
print index
0
5
10
15
Эта ветка немного старая, но у меня это сработало:
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)
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)
Эта функция не просматривает все позиции внутри строки, она не тратит впустую вычислительные ресурсы. Моя попытка:
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')
При поиске большого количества ключевых слов в документе используйте 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 работает быстрее, чем регулярное выражение для большого списка поисковых слов.
Я думаю, что самый чистый способ решения - без библиотек и выходов:
def find_all_occurrences(string, sub):
index_of_occurrences = []
current_index = 0
while True:
current_index = string.find(sub, current_index)
if current_index == -1:
return index_of_occurrences
else:
index_of_occurrences.append(current_index)
current_index += len(sub)
find_all_occurrences(string, substr)
Примечание: find()
метод возвращает-1
когда ничего не находит
Это решение аналогичного вопроса от 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)
Независимо от того, что решения, предоставленные другими, полностью основаны на доступном методе 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 ("Считаете ли вы этот ответ полезным? Тогда проголосуйте за это!", "Это")
если вы хотите использовать без re(regex), тогда:
find_all = lambda _str,_w : [ i for i in range(len(_str)) if _str.startswith(_w,i) ]
string = "test test test test"
print( find_all(string, 'test') ) # >>> [0, 5, 10, 15]
Вот решение, которое я придумал, используя выражение присваивания (новая функция начиная с Python 3.8):
string = "test test test test"
phrase = "test"
start = -1
result = [(start := string.find(phrase, start + 1)) for _ in range(string.count(phrase))]
Выход:
[0, 5, 10, 15]
если вы хотите использовать только numpy, вот решение
import numpy as np
S= "test test test test"
S2 = 'test'
inds = np.cumsum([len(k)+len(S2) for k in S.split(S2)[:-1]])- len(S2)
print(inds)
Питонический путь будет:
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]
>>>
def find_index(string, let):
enumerated = [place for place, letter in enumerate(string) if letter == let]
return enumerated
например:
find_index("hey doode find d", "d")
возвращает:
[4, 7, 13, 15]
def count_substring(string, sub_string):
c=0
for i in range(0,len(string)-2):
if string[i:i+len(sub_string)] == sub_string:
c+=1
return c
if __name__ == '__main__':
string = input().strip()
sub_string = input().strip()
count = count_substring(string, sub_string)
print(count)
Не совсем то, что просил OP, но вы также можете использовать функцию разделения, чтобы получить список, в котором все подстроки не встречаются. OP не указывал конечную цель кода, но если ваша цель - удалить подстроки в любом случае, это может быть простой однострочник. Вероятно, есть более эффективные способы сделать это с более крупными строками; в этом случае предпочтительнее регулярные выражения
# Extract all non-substrings
s = "an-example-string"
s_no_dash = s.split('-')
# >>> s_no_dash
# ['an', 'example', 'string']
# Or extract and join them into a sentence
s_no_dash2 = ' '.join(s.split('-'))
# >>> s_no_dash2
# 'an example string'
Сделал краткий обзор других ответов, поэтому извиняюсь, если это уже есть.
Чтобы найти все вхождения символа в заданной строке и вернуть его в виде словаря, например: hello result : {'h':1, 'e':1, 'l':2, 'o':1}
def count(string):
result = {}
if(string):
for i in string:
result[i] = string.count(i)
return result
return {}
или еще вы делаете, как это
from collections import Counter
def count(string):
return Counter(string)
Разрезая, мы находим все возможные комбинации и добавляем их в список и определяем, сколько раз это происходит, используя 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))
Я столкнулся с той же проблемой и сделал следующее:
hw = 'Hello oh World!'
list_hw = list(hw)
o_in_hw = []
while True:
o = hw.find('o')
if o != -1:
o_in_hw.append(o)
list_hw[o] = ' '
hw = ''.join(list_hw)
else:
print(o_in_hw)
break
Я новичок в кодировании, поэтому вы, вероятно, можете его упростить (и, если планируется использовать постоянно, конечно, сделайте это функцией).
Все и все работает так, как задумано для того, что я делал.
Пожалуйста, посмотрите на код ниже
#!/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)