计算子字符串在字符串中出现的次数

Count how many times a substring appears in a string

提问人:Alice S. 提问时间:10/6/2023 更新时间:10/8/2023 访问量:75

问:

我正在尝试计算子字符串在字符串中出现的次数。

count = 0
stock = []
phrase = "abcdacdeabcf"
sub = "abc"
liphrase = list(phrase) 
lisub = list(sub)

for j in range(0,len(liphrase)-len(lisub)+1):
    for i in range(0,len(lisub)) :
        if liphrase[i+j] == lisub[i]:
            stock.append(liphrase[i+j])
    if stock == lisub:
        count += 1
        stock = []

print(count)

我写了这段代码,但它似乎效果不佳,无法找出问题所在。 我将不胜感激,谢谢:)

python list 循环 if-statement while-loop

评论

2赞 Thierry Lathuille 10/6/2023
“它似乎效果不佳”对不起作用的内容描述不够清晰。请非常具体,使用精心选择的硬编码输入,以及相应的输出与预期输出。

答:

0赞 Yuri R 10/6/2023 #1

代码的主要问题是,在内部循环找不到匹配项的情况下,您忘记重置库存列表。因此,即使一个子字符串不匹配,这些字符仍会累积在库存列表中。

但是,您可以使用标志来确定子字符串是否匹配,而不是使用库存列表来累积字符,然后将其与 lisub 进行比较。如果在循环访问子字符串后该标志仍为 true,则可以递增计数。

下面是代码的修订版本:

count = 0
phrase = "abcdacdeabcf"
sub = "abc"
liphrase = list(phrase)
lisub = list(sub)

for j in range(0, len(liphrase) - len(lisub) + 1):
    match_found = True  # assume a match until proven otherwise
    for i in range(0, len(lisub)):
        if liphrase[i + j] != lisub[i]:
            match_found = False
            break  # exit the inner loop if no match
    if match_found:
        count += 1

print(count)

或者你可以使用 count 方法

phrase = "abcdacdeabcf"
sub = "abc"
count = phrase.count(sub)
print(count)

评论

2赞 Kelly Bundy 10/7/2023
完美的用例,无需重新发明。forelse
0赞 Kelly Bundy 10/7/2023
由于您放弃了列表构建/比较,因此不再需要列表版本。
0赞 Mr. Polywhirl 10/6/2023 #2

您应该能够将每个子字符串与单个循环进行比较:

def count_occurences(phrase: str, sub: str) -> int:
    count = 0
    for i in range(len(phrase) - len(sub) + 1):
        if phrase[i:i+len(sub)] == sub:
            count += 1
    print('DEBUG:', 'Built-in:', phrase.count(sub), '|', 'Custom:', count)
    return count
    
if __name__ == '__main__':
    count = count_occurences('abcdacdeabcf', 'abc')
    print(count) # 2
    print(count_occurences('a', 'a')) # 1

正如 Kelly 在评论中提到的,您可以使用:startswith

def count_occurences(phrase: str, sub: str) -> int:
    count = 0
    for start in range(len(phrase) - len(sub) + 1):
        if phrase.startswith(sub, start):
            count += 1
    return count
    
if __name__ == '__main__':
    print(count_occurences('abcdacdeabcf', 'abc')) # 2
    print(count_occurences('a', 'a')) # 1

下面是一个带有列表理解功能的小代码高尔夫:

''' 74 bytes '''
f=lambda p,s:len([i for i in range(len(p)-len(s)+1) if p.startswith(s,i)])

print(f('abcdacdeabcf', 'abc')) # 2
print(f('a', 'a')) # 1

评论

0赞 Mr. Polywhirl 10/8/2023
@KellyBundy我的错,我错过了。我需要更多的咖啡。
0赞 Kelly Bundy 10/8/2023
顺便说一句,代码高尔夫通常不关心速度,所以你可以删除.(再节省几个字节:-len(s)f=lambda p,s:sum(p.startswith(s,i)for i in range(len(p)+1)))