具有重叠事件的字符串计数

时间:2010-06-03 23:29:06

标签: python string search

计算给定字符串出现次数的最佳方法是什么,包括python中的重叠?这是最明显的方式:

def function(string, str_to_search_for):
      count = 0
      for x in xrange(len(string) - len(str_to_search_for) + 1):
           if string[x:x+len(str_to_search_for)] == str_to_search_for:
                count += 1
      return count


function('1011101111','11')
returns 5

或者python中有更好的方法吗?

23 个答案:

答案 0 :(得分:67)

嗯,这个可能更快,因为它在C中进行比较:

def occurrences(string, sub):
    count = start = 0
    while True:
        start = string.find(sub, start) + 1
        if start > 0:
            count+=1
        else:
            return count

答案 1 :(得分:38)

>>> import re
>>> text = '1011101111'
>>> len(re.findall('(?=11)', text))
5

如果您不想将整个匹配列表加载到内存中,这将永远不会成为问题!如果你真的想要,你可以这样做:

>>> sum(1 for _ in re.finditer('(?=11)', text))
5

作为函数(re.escape确保子字符串不会干扰正则表达式):

>>> def occurrences(text, sub):
        return len(re.findall('(?={0})'.format(re.escape(sub)), text))

>>> occurrences(text, '11')
5

答案 2 :(得分:11)

您也可以尝试使用支持重叠匹配的new Python regex module

import regex as re

def count_overlapping(text, search_for):
    return len(re.findall(search_for, text, overlapped=True))

count_overlapping('1011101111','11')  # 5

答案 3 :(得分:8)

Python的str.count计算非重叠的子串:

In [3]: "ababa".count("aba")
Out[3]: 1

以下是计算重叠序列的几种方法,我相信还有更多方法:)

前瞻性正则表达式

How to find overlapping matches with a regexp?

In [10]: re.findall("a(?=ba)", "ababa")
Out[10]: ['a', 'a']

生成所有子字符串

In [11]: data = "ababa"
In [17]: sum(1 for i in range(len(data)) if data.startswith("aba", i))
Out[17]: 2

答案 4 :(得分:3)

s = "bobobob"
sub = "bob"
ln = len(sub)
print(sum(sub == s[i:i+ln] for i in xrange(len(s)-(ln-1))))

答案 5 :(得分:3)

如何在另一个重叠

的字符串中查找模式

此功能(另一种解决方案!)接收模式和文本。返回一个列表,其中包含位于其位置的所有子字符串。

def occurrences(pattern, text):
    """
    input: search a pattern (regular expression) in a text
    returns: a list of substrings and their positions 
    """
    p = re.compile('(?=({0}))'.format(pattern))
    matches = re.finditer(p, text)
    return [(match.group(1), match.start()) for match in matches]

print (occurrences('ana', 'banana'))
print (occurrences('.ana', 'Banana-fana fo-fana'))
  

[(' ana',1),(' ana',3)]
  [(' Bana',0),(' nana',2),(' fana',7),(' fana', 15)]

答案 6 :(得分:2)

我的答案,关于课程上的鲍勃问题:

s = 'azcbobobegghaklbob'
total = 0
for i in range(len(s)-2):
    if s[i:i+3] == 'bob':
        total += 1
print 'number of times bob occurs is: ', total

答案 7 :(得分:2)

def count_substring(string, sub_string):
    count = 0
    for pos in range(len(string)):
        if string[pos:].startswith(sub_string):
            count += 1
    return count

这可能是最简单的方法。

答案 8 :(得分:1)

一种相当Python化的方法是在这里使用列表理解,尽管这可能不是最有效的。

sequence = 'abaaadcaaaa'
substr = 'aa'

counts = sum([
    sequence.startswith(sub, i) for i in range(len(sequence))
])
print(counts)  # 5

列表将是[False, False, True, False, False, False, True, True, False, False],因为它会检查字符串中的所有索引,并且因为int(True) == 1sum为我们提供了匹配的总数。

答案 9 :(得分:1)

这是我的edX MIT“find bob”*解决方案(*在名为s的字符串中查找“bob”出现次数),它基本计算给定子项的重叠出现次数:

s = 'azcbobobegghakl'
count = 0

while 'bob' in s:
    count += 1 
    s = s[(s.find('bob') + 2):]

print "Number of times bob occurs is: {}".format(count)

答案 10 :(得分:1)

可以使用正则表达式来解决。

import re
def function(string, sub_string):
    match = re.findall('(?='+sub_string+')',string)
    return len(match)

答案 11 :(得分:1)

def count_substring(string, sub_string):
    counter = 0
    for i in range(len(string)):
        if string[i:].startswith(sub_string):
        counter = counter + 1
    return counter

上面的代码只是在整个字符串中循环一次并继续检查是否有任何字符串以正在计数的特定子字符串开头。

答案 12 :(得分:0)

def occurance_of_pattern(text, pattern):
    text_len , pattern_len = len(text), len(pattern)
    return sum(1 for idx in range(text_len - pattern_len + 1) if text[idx: idx+pattern_len] == pattern) 

答案 13 :(得分:0)

计算子字符串出现的一种简单方法是使用count()

>>> s = 'bobob'
>>> s.count('bob')
1

如果知道哪个部分将重叠,则可以使用replace ()查找重叠的字符串:

>>> s = 'bobob'
>>> s.replace('b', 'bb').count('bob')
2

请注意,除了是静态的以外,还有其他限制:

>>> s = 'aaa'
>>> count('aa') # there must be two occurrences
1 
>>> s.replace('a', 'aa').count('aa')
3

答案 14 :(得分:0)

给出

sequence = '1011101111'
sub = "11"

代码

在这种情况下:

sum(x == tuple(sub) for x in zip(sequence, sequence[1:]))
# 5

更一般地说,

windows = zip(*([sequence[i:] for i, _ in enumerate(sequence)][:len(sub)]))
sum(x == tuple(sub) for x in windows)
# 5

或扩展到生成器:

import itertools as it


iter_ = (sequence[i:] for i, _ in enumerate(sequence))
windows = zip(*(it.islice(iter_, None, len(sub))))
sum(x == tuple(sub) for x in windows)

替代

您可以使用more_itertools.locate

import more_itertools as mit


len(list(mit.locate(sequence, pred=lambda *args: args == tuple(sub), window_size=len(sub))))
# 5

答案 15 :(得分:0)

这是使用str.find()的另一个例子,但是很多答案使得它比必要的更复杂:

def occurrences(text, sub):
    c, n = 0, text.find(sub)
    while n != -1:
        c += 1
        n = text.find(sub, n+1)
    return c

In []:
occurrences('1011101111', '11')

Out[]:
5

答案 16 :(得分:0)

如果字符串很大,您希望在摘要中使用Rabin-Karp

  • 子串大小的滚动窗口,在字符串上移动
  • 带有O(1)开销的散列,用于添加和删除(即移动1个字符)
  • 在C中实施或依赖于pypy

答案 17 :(得分:0)

非常接近已接受答案的替代方案,但使用while作为if测试,而不是在循环中包含if

def countSubstr(string, sub):
    count = 0
    while sub in string:
        count += 1
        string = string[string.find(sub) + 1:]
    return count;

这可以避免while True:并且在我看来更清洁

答案 18 :(得分:0)

对于重复的question,我决定将其计算为3乘3并比较字符串,例如

counted = 0

for i in range(len(string)):

    if string[i*3:(i+1)*3] == 'xox':
       counted = counted +1

print counted

答案 19 :(得分:0)

将两个字符串作为输入的函数,并计算字符串中sub出现的次数,包括重叠。为了检查sub是否是子字符串,我使用了in运算符。

def count_Occurrences(string, sub):
    count=0
    for i in range(0, len(string)-len(sub)+1):
        if sub in string[i:i+len(sub)]:
            count=count+1
    print 'Number of times sub occurs in string (including overlaps): ', count

答案 20 :(得分:0)

def count_overlaps (string, look_for):
    start   = 0
    matches = 0

    while True:
        start = string.find (look_for, start)
        if start < 0:
            break

        start   += 1
        matches += 1

    return matches

print count_overlaps ('abrabra', 'abra')

答案 21 :(得分:-2)

sum([ 1 for _ in range(len(string)-len(str_to_search_for)+1) if string[_:_+len(str_to_search_for)] == str_to_search_for])

在列表理解中,我们使用较小字符串长度的滑动窗口一次滑动一个位置的较大字符串。我们可以通过从较大的字符串中减去较小字符串的长度来计算滑动计数。对于每张幻灯片,我们将较大字符串的该部分与较小的字符串进行比较,如果找到匹配则在列表中生成1。列表中所有这些1的总和将给出我们找到的匹配总数。

答案 22 :(得分:-2)

如果您想计算长度为5的排列计数(如果需要调整不同的长度):

def MerCount(s):
  for i in xrange(len(s)-4):
    d[s[i:i+5]] += 1
return d