Python 中字符串中子字符串的重叠计数

Overlapping count of substring in a string in Python

我想找到字符串中子字符串的所有计数(重叠和非重叠)。 我找到了两个答案,其中一个是使用正则表达式,这不是我的本意,另一个比我需要的效率低得多。 我需要这样的东西:

'ababaa'.count('aba') == 2

str.count() 只计算简单的子字符串。我该怎么办?

这样做有用吗?

def count(string, substring):
    n = len(substring)
    cnt = 0
    for i in range(len(string) - n):
        if string[i:i+n] == substring:
            cnt += 1
    return cnt

print count('ababaa', 'aba') # 2

我不知道是否有更有效的解决方案,但这应该可行。

在这里,使用re.finditer()是实现你想要的最好方法。

import re 

def get_substring_count(s, sub_s):
    return sum(1 for m in re.finditer('(?=%s)' % sub_s, s))

get_substring_count('ababaa', 'aba')
# 2 as response
def sliding(a, n):
    return (a[i:i+n] for i in xrange(len(a) - n + 1))

def substring_count(a, b):
    return sum(s == b for s in sliding(a, len(b)))

assert list(sliding('abcde', 3)) == ['abc', 'bcd', 'cde']    
assert substring_count('ababaa', 'aba') == 2
count = len(set([string.find('aba',x) for x in range(len(string)) if string.find('aba',x) >= 0]))

这是您可以使用的函数:

def count(haystack, needle):
    return len([x for x in [haystack[i:j+1] for i in xrange(len(haystack)) for j in xrange(i,len(haystack))] if x == needle])

然后:

>>> count("ababaa", "aba")
2

蛮力方法就是

n = len(needle)
count = sum(haystack[i:i+n] == needle for i in range(len(haystack)-n+1))

(这是有效的,因为在 Python 中,TrueFalse 等同于数字 10 对于大多数用途,包括数学)。

改用正则表达式可以

count = len(re.findall(needle[:1]+"(?="+re.escape(needle[1:])+")",
                       haystack))

(即使用 a(?=ba) 而不是 aba 来查找重叠匹配项)

遍历切片字符串

def count_substring(string, sub_string):
    l = len(sub_string)
    n = len(string)
    count = sum(1 for i in range(n-l+1) if string[i:i+l].count(sub_string)>0 )
    return count

另一种考虑方法是利用 Counter 容器。虽然接受的答案对于较短的字符串是最快的,但如果您在长字符串中搜索相对较短的子字符串,则 Counter 方法开始占据优势。此外,如果您需要重构它以针对同一主字符串执行多个子字符串计数查询,那么 Counter 方法开始看起来更有吸引力

例如,使用 timeit 搜索长度为 3 的子字符串得到以下结果;

主要字符串长度/接受的答案/反方法

6 个字符/4.1us/7.4us

50 个字符/24.4us/25us

150 个字符/70.7us/64.9us

1500 个字符/723us/614us

from collections import Counter

def count_w_overlap(search_string, main_string):
    #Split up main_string into all possible overlap possibilities
    search_len = len(search_string)
    candidates = [main_string[i:i+search_len] for i in range(0, len(main_string) - search_len + 1)]
    #Create the Counter container
    freq_count = Counter(candidates)
    return freq_count[search_string]