Contar o número de ocorrências de uma determinada substring em uma string


201

Como posso contar o número de vezes que uma determinada substring está presente em uma string no Python?

Por exemplo:

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

O que você quer dizer com "número de substring"? A posição da substring? Quantas vezes a substring ocorre? Algo mais?
GreenMatt

2
Esta é uma tarefa de casa? Em caso afirmativo, adicione a tag "lição de casa" à sua pergunta. Além disso, sua pergunta não é muito clara. Responderei o que você parece estar perguntando, mas desconfio que realmente queira descobrir outra coisa.
Jim DeLaHunt

Após o comentário anterior, convém ver: python: como encontrar uma substring em outra string ou recorrências de indexação básica de uma substring em uma string (python) . Como essa parece ser uma duplicata provável, estou votando para fechar.
GreenMatt

@JimDeLaHunt Para os registros, há um exercício sobre isso em cscircles.cemc.uwaterloo.ca/8-remix - consulte Exercício de codificação: contagem de substring .
Nikos Alexandris

Respostas:


334

string.count(substring), como em:

>>> "abcdabcva".count("ab")
2

Atualizar:

Conforme apontado nos comentários, esta é a maneira de fazer isso para ocorrências não sobrepostas . Se você precisar contar ocorrências sobrepostas, é melhor verificar as respostas em: "O regex do Python encontra todas as correspondências sobrepostas? " Ou apenas verificar minha outra resposta abaixo.


14
O que acontece com isso: "GCAAAAAG".count("AAA")que fornece 1, enquanto a resposta correta é 3?
cartunista

12
counté obviamente para correspondências sem sobreposição - o que geralmente é o que se deseja fazer. stackoverflow.com/questions/5616822/... ofertas com sobreposição de partidas - mas um simples, se caros, a expressão é:sum("GCAAAAAGH"[i:].startswith("AAA") for i in range(len("GCAAAAAGH")))
jsbueno

É possível contar / pesquisar várias palavras ao mesmo tempo? como string.count (substring1, substring2)
Sushant Kulkarni

@SushantKulkarni Não. Embora não há uma maneira lógica de fazer tal coisa a: string.count(substring1) + string.count(substring2). Mas lembre-se de que este não é um método eficiente se houver muitas substrings, pois contar cada substring requer uma iteração na string principal.
Faheel 22/11

A ação do @SushantKulkarni ''.join([substring1, substring2]).count(pattern)é mais eficiente do que a solução sugerida acima. Eu verifiquei usando timeit.
Enric Calabuig

23
s = 'arunununghhjj'
sb = 'nun'
results = 0
sub_len = len(sb)
for i in range(len(s)):
    if s[i:i+sub_len] == sb:
        results += 1
print results

4
Explicações adicionais melhorariam sua resposta.
Ryanyuyu

19

Dependendo do que você realmente quer dizer, proponho as seguintes soluções:

  1. Você quer dizer uma lista de sub-strings separadas por espaço e deseja saber qual é o número de posição da sub-string entre todas as sub-strings:

    s = 'sub1 sub2 sub3'
    s.split().index('sub2')
    >>> 1
  2. Você quer dizer a posição de char da sub-string na string:

    s.find('sub2')
    >>> 5
  3. Você quer dizer as contagens (sem sobreposição) de aparência de uma sub-string:

    s.count('sub2')
    >>> 1
    s.count('sub')
    >>> 3

Tente encontrar 'sub' ou 'su'
obohovyk

Eu acho que você quer dizer s.find("su")e se pergunta por que você conseguiu 0? Bem, este é o primeiro índice da sub-string"su" em s. Tente "ub"e você obterá 1, tente por exemplo, "z"e você obterá -1como em nenhuma substring encontrada.
Don Pergunta

Quer dizer que você sempre encontrar apenas o primeiro índice, mas não todos os índices, @ arun-kumar-Khattri gived resposta correta
obohovyk

Estou aliviado que @ arun-kumar-khattri deu a resposta "correta" que você estava procurando. Talvez você deva dar uma olhada adicional nos comentários de jsbueno, às vezes eles respondem a perguntas que você ainda não fez.
Don Pergunta

Como na terceira abordagem. BTW, acho que você deve mencionar que funciona para casos sem sobreposição.
Zeinab Abbasimazar

12

A melhor maneira de encontrar uma sub-string sobreposta em uma determinada string é usar a expressão regular python, que encontrará toda a correspondência sobreposta usando a biblioteca de expressões regulares. Aqui está como fazer isso à esquerda é a substring e à direita você fornecerá a string para corresponder

print len(re.findall('(?=aa)','caaaab'))
3

2
talvez você possa adicionar len (re.findall (f '(? = {sub_string})', 'caaaab')) para inserir a sub string dinamicamente :)
Amresh Giri 18/04/19

10

Para encontrar ocorrências sobrepostas de uma substring em uma string no Python 3, esse algoritmo fará:

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

Eu próprio verifiquei este algoritmo e funcionou.


1
Dica pequena: em vez de dizer "Funciona porque eu verifiquei", você pode incluir um exemplo em um serviço online como repl.it com alguns dados de amostra.
Valentin

1
obrigado pelo seu comentário Valentin! É a minha primeira resposta aqui. Vou me aperfeiçoar com minhas próximas respostas.
precisa

10

Você pode contar a frequência de duas maneiras:

  1. Usando o count()em str:

    a.count(b)

  2. Ou você pode usar:

    len(a.split(b))-1

Onde aé a string e ba substring cuja frequência deve ser calculada.


7

A melhor resposta atual que envolve o método countrealmente não conta para ocorrências sobrepostas e também não se importa com sub-strings vazias. Por exemplo:

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

A primeira resposta 2não deve ser 1, se considerarmos as substrings sobrepostas. Quanto à segunda resposta, é melhor se uma sub-string vazia retornar 0 como a resposta.

O código a seguir cuida dessas coisas.

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

Agora, quando executamos:

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

6

Cenário 1: Ocorrência de uma palavra em uma frase. por exemplo: str1 = "This is an example and is easy". A ocorrência da palavra "é". deixastr2 = "is"

count = str1.count(str2)

Cenário 2: Ocorrência de padrão em uma frase.

string = "ABCDCDC"
substring = "CDC"

def count_substring(string,sub_string):
    len1 = len(string)
    len2 = len(sub_string)
    j =0
    counter = 0
    while(j < len1):
        if(string[j] == sub_string[0]):
            if(string[j:j+len2] == sub_string):
                counter += 1
        j += 1

    return counter

Obrigado!


realmente precisamos dessa verificação se (string [j] == sub_string [0]):? não é coberto automaticamente na condição if subsequente?
AnandViswanathan89 13/02/19

AnandViswanathan89, Both se forem necessárias condições, if (string [j] == sub_string [0]) verifica a correspondência de caracteres inicial na string principal, que deve ser executada para todos os caracteres da string principal e if (string [ j: j + len2] == sub_string) executa a ocorrência de substring. Se for para a primeira ocorrência, então a segunda, se a condição for suficiente.
Amith VV 14/02/19

4

A pergunta não é muito clara, mas responderei o que você está perguntando, na superfície.

Uma sequência S, que tem L caracteres e onde S [1] é o primeiro caractere da sequência e S [L] é o último caractere, possui as seguintes substrings:

  • A cadeia nula ''. Existe um desses.
  • Para todo valor A de 1 a L, para todo valor B de A a L, a sequência S [A] .. S [B] (inclusive). Existem L + L-1 + L-2 + ... 1 dessas cadeias, para um total de 0,5 * L * (L + 1).
  • Observe que o segundo item inclui S [1] .. S [L], ou seja, toda a sequência original S.

Portanto, existem 0,5 * L * (L + 1) + 1 substrings dentro de uma cadeia de comprimento L. Renderize essa expressão em Python e você terá o número de substrings presentes na cadeia.


4

Uma maneira é usar re.subn. Por exemplo, para contar o número de ocorrências de 'hello'qualquer combinação de casos, você pode:

import re
_, count = re.subn(r'hello', '', astring, flags=re.I)
print('Found', count, 'occurrences of "hello"')

Palavra para mim, obrigado. @antosh, por que não aceitar uma resposta?
Mawg diz restabelecer Monica

2

Manterei minha resposta aceita como a "maneira simples e óbvia de fazer isso" - no entanto, isso não cobre ocorrências sobrepostas. A descoberta dessas informações pode ser feita de forma ingênua, com várias verificações das fatias - como em: sum ("GCAAAAAGH" [i:]. Começa com ("AAA") para i no intervalo (len ("GCAAAAAGH")))

(que produz 3) - isso pode ser feito usando truques com expressões regulares, como pode ser visto no regex do Python, encontrar todas as correspondências sobrepostas? - e também pode resultar em golfe com código fino - Essa é a minha contagem "feita à mão" para ocorrência de sobreposição de padrões em uma string que tenta não ser extremamente ingênua (pelo menos não cria novos objetos de string em cada interação):

def find_matches_overlapping(text, pattern):
    lpat = len(pattern) - 1
    matches = []
    text = array("u", text)
    pattern = array("u", pattern)
    indexes = {}
    for i in range(len(text) - lpat):
        if text[i] == pattern[0]:
            indexes[i] = -1
        for index, counter in list(indexes.items()):
            counter += 1
            if text[i] == pattern[counter]:
                if counter == lpat:
                    matches.append(index)
                    del indexes[index]
                else:
                    indexes[index] = counter
            else:
                del indexes[index]
    return matches

def count_matches(text, pattern):
    return len(find_matches_overlapping(text, pattern))

2

Ocorrências sobrepostas:

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')

Resultados:

my maaather lies over the oceaaan
6
4
2

2

Para contagem sobreposta, podemos usar use:

def count_substring(string, sub_string):
    count=0
    beg=0
    while(string.find(sub_string,beg)!=-1) :
        count=count+1
        beg=string.find(sub_string,beg)
        beg=beg+1
    return count

Para casos sem sobreposição, podemos usar a função count ():

string.count(sub_string)

2

Que tal um one-liner com uma lista de compreensão? Tecnicamente, com 93 caracteres, poupe-me o purismo de PEP-8. A resposta regex.findall é a mais legível se for um trecho de código de alto nível. Se você está construindo algo de baixo nível e não quer dependências, este é bastante enxuto e mesquinho. Estou dando a resposta sobreposta. Obviamente, basta usar count como a resposta de pontuação mais alta se não houver sobreposição.

def count_substring(string, sub_string):
    return len([i for i in range(len(string)) if string[i:i+len(sub_string)] == sub_string])

2

Se você quiser contar todas as sub-strings (incluindo sobrepostas), use este método.

import re
def count_substring(string, sub_string):
    regex = '(?='+sub_string+')'
    # print(regex)
    return len(re.findall(regex,string))

1

Se você deseja descobrir a contagem de substring dentro de qualquer string; use o código abaixo. É fácil entender o código, por isso pulei os comentários. :)

string=raw_input()
sub_string=raw_input()
start=0
answer=0
length=len(string)
index=string.find(sub_string,start,length)
while index<>-1:
    start=index+1
    answer=answer+1
    index=string.find(sub_string,start,length)
print answer

0

Não tenho certeza se isso já é algo analisado, mas pensei nisso como uma solução para uma palavra que é 'descartável':

for i in xrange(len(word)):
if word[:len(term)] == term:
    count += 1
word = word[1:]

print count

Onde palavra é a palavra que você está pesquisando e termo é o termo que você está procurando


0
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)

2
Talvez você possa explicar como essa solução é diferente da outra. Existe um caso especial que é capaz de resolver?
precisa saber é

2
Embora esse código possa responder à pergunta, fornecer um contexto adicional sobre como e / ou por que resolve o problema melhoraria o valor a longo prazo da resposta.
Donald Duck

0
import re
d = [m.start() for m in re.finditer(seaching, string)] 
print (d)

Ele encontra o número de vezes que a sub-string é encontrada na string e exibe o índice.


import re d = [m.start () para m no re.finditer (st3, st2)] #finding o número de vezes que a sub string encontrada na string e exibe o índice print (d)
Bhaskar Reddi K

0
my_string = """Strings are amongst the most popular data types in Python. 
               We can create the strings by enclosing characters in quotes.
               Python treats single quotes the same as double quotes."""

Count = my_string.lower().strip("\n").split(" ").count("string")
Count = my_string.lower().strip("\n").split(" ").count("strings")
print("The number of occurance of word String is : " , Count)
print("The number of occurance of word Strings is : " , Count)

0

Arriscar um voto negativo, porque mais de 2 pessoas já forneceram esta solução. Eu até votei em um deles. Mas o meu é provavelmente o mais fácil para os novatos entenderem.

def count_substring(string, sub_string):
    slen  = len(string)
    sslen = len(sub_string)
    range_s = slen - sslen + 1
    count = 0
    for i in range(range_s):
        if (string[i:i+sslen] == sub_string):
            count += 1
    return count

0

Para uma string simples com delimitação de espaço, o uso do Dict seria bastante rápido, veja o código abaixo

def getStringCount(mnstr:str, sbstr:str='')->int:
    """ Assumes two inputs string giving the string and 
        substring to look for number of occurances 
        Returns the number of occurances of a given string
    """
    x = dict()
    x[sbstr] = 0
    sbstr = sbstr.strip()
    for st in mnstr.split(' '):
        if st not in [sbstr]:
            continue
        try:
            x[st]+=1
        except KeyError:
            x[st] = 1
    return x[sbstr]

s = 'foo bar foo test one two three foo bar'
getStringCount(s,'foo')

0

Você pode usar o startswithmétodo:

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

0

A lógica abaixo funcionará para todas as cadeias e caracteres especiais

def cnt_substr(inp_str, sub_str):
    inp_join_str = ''.join(inp_str.split())
    sub_join_str = ''.join(sub_str.split())

    return inp_join_str.count(sub_join_str)

print(cnt_substr("the sky is   $blue and not greenthe sky is   $blue and not green", "the sky"))

0

Aqui está a solução no Python 3 e não diferencia maiúsculas de minúsculas:

s = 'foo bar foo'.upper()
sb = 'foo'.upper()
results = 0
sub_len = len(sb)
for i in range(len(s)):
    if s[i:i+sub_len] == sb:
        results += 1
print(results)

0
j = 0
    while i < len(string):
        sub_string_out = string[i:len(sub_string)+j]
        if sub_string == sub_string_out:
            count += 1
        i += 1
        j += 1
    return count

2
Embora todas as respostas sejam apreciadas, as respostas somente em código tendem a não explicar muito bem o assunto. Por favor, adicione algum contexto.
creyD

0
#counting occurence of a substring in another string (overlapping/non overlapping)
s = input('enter the main string: ')# e.g. 'bobazcbobobegbobobgbobobhaklpbobawanbobobobob'
p=input('enter the substring: ')# e.g. 'bob'

counter=0
c=0

for i in range(len(s)-len(p)+1):
    for j in range(len(p)):
        if s[i+j]==p[j]:
            if c<len(p):
                c=c+1
                if c==len(p):
                    counter+=1
                    c=0
                    break
                continue
        else:
            break
print('number of occurences of the substring in the main string is: ',counter)

0
s = input('enter the main string: ')
p=input('enter the substring: ')
l=[]
for i in range(len(s)):
    l.append(s[i:i+len(p)])
print(l.count(p))

0

Isso faz uma lista de todas as ocorrências (também sobrepostas) na string e as conta

def num_occ(str1, str2):
    l1, l2 = len(str1), len(str2)
    return len([str1[i:i + l2] for i in range(l1 - l2 + 1) if str1[i:i + l2] == str2])

Exemplo:

str1 ='abcabcd'
str2 = 'bc'

criará esta lista, mas salvará apenas os valores BOLD :

[ab, bc , ca, ab, bc , cd]

que retornará:

len([bc, bc])

1
Por favor, considere adicionar pelo menos alguma explicação, como se essa resposta à pergunta
fosse

0

Aqui está uma solução que funciona para ocorrências não sobrepostas e sobrepostas. Para esclarecer: uma substring sobreposta é aquela cujo último caractere é idêntico ao seu primeiro caractere.

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.