[英]Find all Occurences of Every Substring in String
我試圖在主字符串(所有長度)中找到所有出現的子字符串。 我的函數接受一個字符串,然后返回每個子字符串的字典(當然會多次出現)和它出現的次數(字典的格式: {substring: # of occurrences, ...}
)。 我正在使用collections.Counter(s)
來幫助我。
這是我的功能:
from collections import Counter
def patternFind(s):
patterns = {}
for index in range(1, len(s)+1)[::-1]:
d = nChunks(s, step=index)
parts = dict(Counter(d))
patterns.update({elem: parts[elem] for elem in parts.keys() if parts[elem] > 1})
return patterns
def nChunks(iterable, start=0, step=1):
return [iterable[i:i+step] for i in range(start, len(iterable), step)]
我有一個字符串, data
有大約2500個隨機字母(按隨機順序)。 但是,有2個字符串插入其中(隨機點)。 說這個字符串是'TEST'。 data.count('TEST')
返回2.但是, patternFind(data)['TEST']
給了我一個KeyError
。 因此,我的程序沒有檢測到它中的兩個字符串。
我做錯了什么? 謝謝!
編輯:我創建測試實例的方法:
def createNewTest():
n = randint(500, 2500)
x, y = randint(500, n), randint(500, n)
s = ''
for i in range(n):
s += choice(uppercase)
if i == x or i == y: s += "TEST"
return s
除了你描述的count()
方法之外,正則表達式是一個明顯的選擇
import re
needle = r'TEST'
haystack = 'khjkzahklahjTESTkahklaghTESTjklajhkhzkhjkzahklahjTESTkahklagh'
pattern = re.compile(needle)
print len(re.findall(pattern, haystack))
如果您需要構建子字符串的字典,可能只能使用這些字符串的子集。 假設你知道needle
你正在尋找的data
,那么你只需要串的字典data
是相同長度的needle
。 這非常快。
from collections import Counter
needle = "TEST"
def gen_sub(s, len_chunk):
for start in range(0, len(s)-len_chunk+1):
yield s[start:start+len_chunk]
data = 'khjkzahklahjTESTkahklaghTESTjklajhkhzkhjkzahklahjTESTkahklaghTESz'
parts = Counter([sub for sub in gen_sub(data, len(needle))])
print parts[needle]
如果你需要計算所有可能的子串,這可行,但它很慢:
from collections import Counter
def gen_sub(s):
for start in range(0, len(s)):
for end in range(start+1, len(s)+1):
yield s[start:end]
data = 'khjkzahklahjTESTkahklaghTESTjklajhkhz'
parts = Counter([sub for sub in gen_sub(data)])
print parts['TEST']
子串生成器改編自: https : //stackoverflow.com/a/8305463/1290420
雖然jurgenreza解釋了為什么你的程序不起作用,但解決方案仍然很慢。 如果你只檢查子s
,而您知道, s[:-1]
重復,你會得到更快的解決方案(通常是一百倍更快,更多):
from collections import defaultdict
def pfind(prefix, sequences):
collector = defaultdict(list)
for sequence in sequences:
collector[sequence[0]].append(sequence)
for item, matching_sequences in collector.items():
if len(matching_sequences) >= 2:
new_prefix = prefix + item
yield (new_prefix, len(matching_sequences))
for r in pfind(new_prefix, [sequence[1:] for sequence in matching_sequences]):
yield r
def find_repeated_substrings(s):
s0 = s + " "
return pfind("", [s0[i:] for i in range(len(s))])
如果你想要一個字典,你可以這樣稱呼它:
result = dict(find_repeated_substrings(s))
在我的機器上,對於2247個元素的運行,它需要0.02秒,而原始(校正的)解決方案需要12.72秒。
(請注意,這是一個相當天真的實現;使用索引代替子串應該更快。)
編輯:以下變體適用於其他序列類型(不僅僅是字符串)。 此外,它不需要sentinel元素。
from collections import defaultdict
def pfind(s, length, ends):
collector = defaultdict(list)
if ends[-1] >= len(s):
del ends[-1]
for end in ends:
if end < len(s):
collector[s[end]].append(end)
for key, matching_ends in collector.items():
if len(matching_ends) >= 2:
end = matching_ends[0]
yield (s[end - length: end + 1], len(matching_ends))
for r in pfind(s, length + 1, [end + 1 for end in matching_ends if end < len(s)]):
yield r
def find_repeated_substrings(s):
return pfind(s, 0, list(range(len(s))))
這仍然存在很長的子串將超過遞歸深度的問題。 您可能想要捕獲異常。
在這里,您可以找到一個解決方案,該解決方案使用string.find()
周圍的遞歸包裝器來搜索主字符串中子字符串的所有出現。 collectallchuncks()
函數返回一個defaultdict
所有子字符串都作為鍵,每個子字符串返回在主字符串中找到子字符串的所有索引的列表。
import collections
# Minimum substring size, may be 1
MINSIZE = 3
# Recursive wrapper
def recfind(p, data, pos, acc):
res = data.find(p, pos)
if res == -1:
return acc
else:
acc.append(res)
return recfind(p, data, res+1, acc)
def collectallchuncks(data):
res = collections.defaultdict(str)
size = len(data)
for base in xrange(size):
for seg in xrange(MINSIZE, size-base+1):
chunk = data[base:base+seg]
if data.count(chunk) > 1:
res[chunk] = recfind(chunk, data, 0, [])
return res
if __name__ == "__main__":
data = 'khjkzahklahjTESTkahklaghTESTjklajhkhzkhjkzahklahjTESTkahklaghTESz'
allchuncks = collectallchuncks(data)
print 'TEST', allchuncks['TEST']
print 'hklag', allchuncks['hklag']
編輯:如果你只需要主字符串中每個子字符串的出現次數,你可以很容易地獲得它去除遞歸函數:
import collections
MINSIZE = 3
def collectallchuncks2(data):
res = collections.defaultdict(str)
size = len(data)
for base in xrange(size):
for seg in xrange(MINSIZE, size-base+1):
chunk = data[base:base+seg]
cnt = data.count(chunk)
if cnt > 1:
res[chunk] = cnt
return res
if __name__ == "__main__":
data = 'khjkzahklahjTESTkahklaghTESTjklajhkhzkhjkzahklahjTESTkahklaghTESz'
allchuncks = collectallchuncks2(data)
print 'TEST', allchuncks['TEST']
print 'hklag', allchuncks['hklag']
問題出在你的nChunks
函數中。 它沒有給你所有必要的塊。
讓我們考慮一個測試字符串:
s='1test2345test'
對於大小為4的塊,你的nChunks
函數給出了這個輸出:
>>>nChunks(s, step=4)
['1tes', 't234', '5tes', 't']
但你真正想要的是:
>>>def nChunks(iterable, start=0, step=1):
return [iterable[i:i+step] for i in range(len(iterable)-step+1)]
>>>nChunks(s, step=4)
['1tes', 'test', 'est2', 'st23', 't234', '2345', '345t', '45te', '5tes', 'test']
你可以看到這種方式有兩個'test'
塊,你的patternFind(s)
將像魅力一樣工作:
>>> patternFind(s)
{'tes': 2, 'st': 2, 'te': 2, 'e': 2, 't': 4, 'es': 2, 'est': 2, 'test': 2, 's': 2}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.