如何计算给定子字符串在Python字符串中出现的次数?

例如:

>>> 'foo bar foo'.numberOfOccurrences('foo')
2

若要获取子字符串的索引,请参见如何查找子字符串的所有出现?。


当前回答

目前涉及方法计数的最佳答案并不能真正计算重叠出现的次数,也不关心空子字符串。 例如:

>>> a = 'caatatab'
>>> b = 'ata'
>>> print(a.count(b)) #overlapping
1
>>>print(a.count('')) #empty string
9

如果我们考虑重叠的子字符串,第一个答案应该是2而不是1。 对于第二个答案,如果空子字符串返回0作为asnwer会更好。

下面的代码处理这些事情。

def num_of_patterns(astr,pattern):
    astr, pattern = astr.strip(), pattern.strip()
    if pattern == '': return 0

    ind, count, start_flag = 0,0,0
    while True:
        try:
            if start_flag == 0:
                ind = astr.index(pattern)
                start_flag = 1
            else:
                ind += 1 + astr[ind+1:].index(pattern)
            count += 1
        except:
            break
    return count

现在当我们运行它时:

>>>num_of_patterns('caatatab', 'ata') #overlapping
2
>>>num_of_patterns('caatatab', '') #empty string
0
>>>num_of_patterns('abcdabcva','ab') #normal
2

其他回答

string="abc"
mainstr="ncnabckjdjkabcxcxccccxcxcabc"
count=0
for i in range(0,len(mainstr)):
    k=0
    while(k<len(string)):
        if(string[k]==mainstr[i+k]):
            k+=1
        else:
            break   
    if(k==len(string)):
        count+=1;   
print(count)

这个问题不是很清楚,但我可以回答你表面上的问题。

一个长度为L个字符的字符串S,其中S[1]是字符串的第一个字符,S[L]是最后一个字符,它有以下子字符串:

空字符串”。这里有一个。 对于从1到L的每一个值A,对于从A到L的每一个值B,字符串S[A]..S[B] (包容)。有L + L-1 + L-2 +…1个字符串,对于a 共0.5*L*(L+1)。 注意,第二项包括S[1]..S[L], 即整个原始字符串S。

所以,在长度为L的字符串中有0.5*L*(L+1) +1个子字符串,在Python中呈现这个表达式,你就有了字符串中出现的子字符串的数量。

这里有一个解决方案,适用于非重叠和重叠的情况。为了澄清:重叠子字符串是指其最后一个字符与其第一个字符相同的子字符串。

def substr_count(st, sub):
    # If a non-overlapping substring then just
    # use the standard string `count` method
    # to count the substring occurences
    if sub[0] != sub[-1]:
        return st.count(sub)

    # Otherwise, create a copy of the source string,
    # and starting from the index of the first occurence
    # of the substring, adjust the source string to start
    # from subsequent occurences of the substring and keep
    # keep count of these occurences
    _st = st[::]
    start = _st.index(sub)
    cnt = 0

    while start is not None:
        cnt += 1
        try:
            _st = _st[start + len(sub) - 1:]
            start = _st.index(sub)
        except (ValueError, IndexError):
            return cnt

    return cnt

使用Python 3.8中引入的赋值操作符,我们可以编写一个简短的函数,在循环中使用str.find()来查找字符串中目标子字符串的重叠实例。已经有一些其他的解决方案使用相同的方法,但这个更短,更快。

赋值表达式不仅用于在last-found实例之后的字符处开始下一个查找操作,还为while循环提供了终端表达式。Str.find()如果没有找到子字符串,则返回-1,在此基础上加上1将得到0,这是false,因此在没有找到更多匹配时退出循环。

# count overlapping occurrences of a substring in a string
def count_overlapping(haystack, needle, start=0, count=0):
    while start := haystack.find(needle, start) + 1:
        count += 1
    return count

print(count_overlapping("moomoooo", "oo"))    # 4

为了进一步优化性能,我们可以查阅草堆。在循环外找到一次,并将其存储在一个局部变量中。这将是更快时,有超过一对夫妇的比赛。

# count overlapping occurrences of a substring in a string
def count_overlapping(haystack, needle, start=0, count=0):
    haystack_find = haystack.find
    while start := haystack_find(needle, start) + 1:
        count += 1
    return count

重叠出现:

def olpcount(string,pattern,case_sensitive=True):
    if case_sensitive != True:
        string  = string.lower()
        pattern = pattern.lower()
    l = len(pattern)
    ct = 0
    for c in range(0,len(string)):
        if string[c:c+l] == pattern:
            ct += 1
    return ct

test = 'my maaather lies over the oceaaan'
print test
print olpcount(test,'a')
print olpcount(test,'aa')
print olpcount(test,'aaa')

结果:

my maaather lies over the oceaaan
6
4
2