Policz liczbę wystąpień danego podłańcucha w ciągu

201

Jak mogę policzyć, ile razy podciąg jest obecny w ciągu w Pythonie?

Na przykład:

>>> 'foo bar foo'.numberOfOccurrences('foo')
2
Santosh
źródło
Co rozumiesz przez „liczbę podciągów”? Pozycja podciągu? Ile razy występuje substring? Coś innego?
GreenMatt
2
Czy to zadanie domowe? Jeśli tak, dodaj tag „zadanie domowe” do swojego pytania. Twoje pytanie również nie jest jasne. Odpowiem na to, o co pytasz, ale podejrzewam, że naprawdę chcesz dowiedzieć się czegoś innego.
Jim DeLaHunt
Po poprzednim komentarzu możesz chcieć zobaczyć: python: Jak znaleźć podciąg w innym ciągu lub Podstawowe indeksowanie powtórzeń podłańcucha w ciągu (python) . Ponieważ wydaje się to być duplikatem jednego z nich, głosuję za jego zamknięciem.
GreenMatt
@JimDeLaHunt Aby uzyskać informacje o rekordach, w cscircles.cemc.uwaterloo.ca/8-remix znajduje się ćwiczenie na ten temat - patrz Ćwiczenie z kodowaniem: liczenie podciągów .
Nikos Alexandris

Odpowiedzi:

334

string.count(substring), jak w:

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

Aktualizacja:

Jak wskazano w komentarzach, jest to sposób na zrobienie tego w przypadku nie nakładających się zdarzeń. Jeśli chcesz policzyć nakładające się wystąpienia, lepiej sprawdź odpowiedzi na: „ Python regex znajduje wszystkie nakładające się dopasowania? ” Lub po prostu sprawdź moją drugą odpowiedź poniżej.

jsbueno
źródło
14
Co z tym: "GCAAAAAG".count("AAA")co daje 1, a prawidłowa odpowiedź to 3?
rysownik
12
countjest oczywiście dla meczów, które się nie pokrywają - co najczęściej chce się robić. stackoverflow.com/questions/5616822/… dotyczy nakładających się dopasowań - ale proste, choć drogie, wyrażenie to:sum("GCAAAAAGH"[i:].startswith("AAA") for i in range(len("GCAAAAAGH")))
jsbueno
Czy można policzyć / wyszukać wiele słów jednocześnie? like string.count (substring1, substring2)
Sushant Kulkarni
@SushantKulkarni nr Choć istnieje jeden logiczny sposób robi coś takiego: string.count(substring1) + string.count(substring2). Pamiętaj jednak, że nie jest to skuteczna metoda, jeśli istnieje wiele podciągów, ponieważ zliczanie każdego z podciągów wymaga iteracji po głównym ciągu.
Faheel
@SushantKulkarni robi ''.join([substring1, substring2]).count(pattern)bardziej wydajne niż rozwiązanie sugerowane powyżej. Sprawdziłem za pomocą 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
Arun Kumar Khattri
źródło
4
Dodatkowe wyjaśnienie poprawi twoją odpowiedź.
ryanyuyu
19

W zależności od tego, co naprawdę masz na myśli, proponuję następujące rozwiązania:

  1. Masz na myśli listę rozdzielonych spacjami podciągów i chcesz wiedzieć, jaki jest numer pozycji podciągu wśród wszystkich podciągów:

    s = 'sub1 sub2 sub3'
    s.split().index('sub2')
    >>> 1
  2. Masz na myśli pozycję char podciągu w ciągu:

    s.find('sub2')
    >>> 5
  3. Masz na myśli (nie nakładające się) liczby wystąpień su-bingu:

    s.count('sub2')
    >>> 1
    s.count('sub')
    >>> 3
Don Pytanie
źródło
Spróbuj znaleźć „sub” lub „su”
obohovyk
Myślę, że masz na myśli s.find("su")i zastanawiasz się, dlaczego masz 0? To jest pierwszy indeks podciągu "su"w s. Spróbuj, "ub"a dostaniesz 1, spróbuj np. "z"A otrzymasz -1tak, jak w przypadku braku podciągów.
Don Pytanie
Mam na myśli, że zawsze znajdziesz tylko pierwszy indeks, ale nie wszystkie indeksy, @ arun-kumar-khattri udzielił poprawnej odpowiedzi
obohovyk
Ulżyło mi, że @ arun-kumar-khattri udzielił „poprawnej” odpowiedzi, której szukałeś. Może powinieneś przyjrzeć się komentarzom jsbueno, czasem odpowiadają one na pytania, których jeszcze nie zadałeś.
Don Pytanie
Jak w przypadku trzeciego podejścia. BTW, myślę, że powinieneś wspomnieć, że to działa w przypadkach nie nakładających się.
Zeinab Abbasimazar
12

Najlepszym sposobem na znalezienie nakładającego się podciągu w danym ciągu jest użycie wyrażenia regularnego python, które znajdzie wszystkie pasujące nakładki za pomocą biblioteki wyrażeń regularnych. Oto jak to zrobić po lewej stronie jest podciąg, a po prawej podasz ciąg znaków, aby dopasować

print len(re.findall('(?=aa)','caaaab'))
3
Deepak Yadav
źródło
2
może mógłbyś dodać len (re.findall (f '(? = {sub_string})', 'caaaab')), aby dynamicznie wstawiać ciąg podrzędny :)
Amresh Giri
10

Aby znaleźć nakładające się wystąpienia podciągu w ciągu znaków w Pythonie 3, ten algorytm wykona:

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  

Sam sprawdziłem ten algorytm i zadziałał.

Bharath Kumar R.
źródło
1
Mała wskazówka: Zamiast powiedzieć „To działa, ponieważ to sprawdziłem”, możesz dołączyć przykładowy serwis internetowy, taki jak repl.it, z przykładowymi danymi.
Valentin
1
dziękuję za komentarz Valentin! To moja pierwsza odpowiedź tutaj. Poprawię się od następnych odpowiedzi.
Bharath Kumar R
10

Możesz policzyć częstotliwość na dwa sposoby:

  1. Korzystanie z count()in str:

    a.count(b)

  2. Lub możesz użyć:

    len(a.split(b))-1

Gdzie ajest ciąg znaków i bpodciąg, którego częstotliwość należy obliczyć.

Anuj Gupta
źródło
7

Obecna najlepsza odpowiedź dotycząca metody counttak naprawdę nie liczy się dla nakładających się wystąpień i nie przejmuje się również pustymi podciągami. Na przykład:

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

Pierwsza odpowiedź powinna być 2nie 1, jeśli weźmiemy pod uwagę nakładających podciągi. Jeśli chodzi o drugą odpowiedź, lepiej, jeśli pusty ciąg podrzędny zwraca 0 jako asnwer.

Poniższy kod zajmuje się tymi rzeczami.

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

Teraz, kiedy go uruchomimy:

>>>num_of_patterns('caatatab', 'ata') #overlapping
2
>>>num_of_patterns('caatatab', '') #empty string
0
>>>num_of_patterns('abcdabcva','ab') #normal
2
Nuhman
źródło
6

Scenariusz 1: Występowanie słowa w zdaniu. np str1 = "This is an example and is easy". : Występowanie słowa „to”. pozwalastr2 = "is"

count = str1.count(str2)

Scenariusz 2: Występowanie wzoru w zdaniu.

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

Dzięki!

Amith VV
źródło
czy naprawdę potrzebujemy tej kontroli, jeśli (string [j] == sub_string [0]):? czy nie jest to automatycznie pokrywane później, jeśli warunek?
AnandViswanathan89,
AnandViswanathan89, Zarówno jeśli warunki są wymagane, jeśli (ciąg [j] == sub_string [0]) sprawdza początkowe dopasowanie znaków w głównym ciągu, które należy wykonać dla wszystkich znaków głównego ciągu i if (ciąg [ j: j + len2] == sub_string) wykonuje wystąpienie podłańcucha. Jeśli jest to pierwsze wystąpienie, to drugie, jeśli warunek byłby wystarczający.
Amith VV
4

Pytanie nie jest bardzo jasne, ale odpowiem na to, o co pytacie na pozór.

Ciąg S, który ma długość L, i gdzie S [1] jest pierwszym znakiem ciągu, a S [L] jest ostatnim znakiem, ma następujące podciągi:

  • Ciąg zerowy „”. Jest jeden z nich.
  • Dla każdej wartości A od 1 do L, dla każdej wartości B od A do L ciąg S [A] .. S [B] (włącznie). Istnieje L + L-1 + L-2 + ... 1 z tych ciągów, w sumie 0,5 * L * (L + 1).
  • Zauważ, że drugi element zawiera S [1] .. S [L], czyli cały oryginalny ciąg S.

Tak więc istnieje 0,5 * L * (L + 1) + 1 podciągów w ciągu o długości L. Renderuj to wyrażenie w Pythonie, a liczba podciągów jest obecna w ciągu.

Jim DeLaHunt
źródło
4

Jednym ze sposobów jest użycie re.subn. Na przykład, aby policzyć liczbę wystąpień 'hello'w dowolnej kombinacji przypadków, możesz:

import re
_, count = re.subn(r'hello', '', astring, flags=re.I)
print('Found', count, 'occurrences of "hello"')
Eugene Yarmash
źródło
Słowo dla mnie, dzięki. @santosh, dlaczego nie zaakceptować odpowiedzi?
Mawg mówi o przywróceniu Moniki
2

Zachowam przyjętą odpowiedź jako „prosty i oczywisty sposób na zrobienie tego” - nie obejmuje to jednak nakładających się zdarzeń. Odkrycie można wykonać naiwnie, z wielokrotnym sprawdzaniem wycinków - jak w: sum („GCAAAAAGH” [i:]. Zaczyna się od („AAA”) dla i w zakresie (len („GCAAAAAGH”)))

(co daje 3) - można tego dokonać poprzez podstępne użycie wyrażeń regularnych, jak widać w wyrażeniu regularnym Python znaleźć wszystkie pokrywające się dopasowania? - i może również sprawić, że gra w golfa będzie świetna. - To mój „ręczny” sposób liczenia się z nakładaniem się bieżących wzorów w ciągu, który stara się nie być wyjątkowo naiwny (przynajmniej nie tworzy nowych obiektów w ciągu przy każdej interakcji):

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))
jsbueno
źródło
2

Nakładające się zdarzenia:

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

Wyniki:

my maaather lies over the oceaaan
6
4
2
Fyngyrz
źródło
2

Do nakładania się możemy użyć użycia:

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

W przypadku nie nakładających się przypadków możemy użyć funkcji count ():

string.count(sub_string)
Dhiraj Dwivedi
źródło
2

Co powiesz na linijkę ze zrozumieniem listy? Technicznie jego 93 znaki długości, oszczędzają mi puryzmu PEP-8. Odpowiedź regex.findall jest najbardziej czytelna, jeśli jest to fragment kodu wysokiego poziomu. Jeśli budujesz coś na niskim poziomie i nie chcesz zależności, ten jest dość chudy i złośliwy. Podaję pokrywającą się odpowiedź. Oczywiście po prostu użyj liczenia jak odpowiedzi o najwyższym wyniku, jeśli nie zachodzi na siebie.

def count_substring(string, sub_string):
    return len([i for i in range(len(string)) if string[i:i+len(sub_string)] == sub_string])
Ryan Dines
źródło
2

Jeśli chcesz policzyć wszystkie podłańcuchy (w tym nakładające się), skorzystaj z tej metody.

import re
def count_substring(string, sub_string):
    regex = '(?='+sub_string+')'
    # print(regex)
    return len(re.findall(regex,string))
Rahul Verma
źródło
1

Jeśli chcesz sprawdzić liczbę podciągów w dowolnym łańcuchu; użyj poniższego kodu. Kod jest łatwy do zrozumienia, dlatego pominąłem komentarze. :)

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
Hemant
źródło
0

Nie jestem pewien, czy na to już spojrzeliśmy, ale pomyślałem o tym jako rozwiązaniu dla słowa, które jest „jednorazowe”:

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

print count

Gdzie słowo jest słowem, którego szukasz, a terminem jest termin, którego szukasz

Alan Vinton
źródło
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)
kamran shaik
źródło
2
Może mógłbyś wyjaśnić, czym to rozwiązanie różni się od drugiego, czy jest jakiś szczególny przypadek, który jest w stanie rozwiązać?
mpaskov
2
Chociaż ten kod może odpowiedzieć na pytanie, zapewnienie dodatkowego kontekstu dotyczącego tego, jak i / lub dlaczego rozwiązuje problem, poprawiłoby długoterminową wartość odpowiedzi.
Kaczor Donald
0
import re
d = [m.start() for m in re.finditer(seaching, string)] 
print (d)

Znajduje to liczbę razy, gdy podciąg znajduje się w ciągu i wyświetla indeks.

Bhaskar Reddi K.
źródło
import re d = [m.start () dla m in re.finditer (st3, st2)] #wskazanie liczby znalezionych podciągów w ciągu i wyświetlenie indeksu wydruku (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)
Vinay Kumar Kuresi
źródło
0

Ryzykując negatywną opinię, ponieważ 2+ inni już dostarczyli to rozwiązanie. Głosowałem nawet za jednym z nich. Ale mój jest prawdopodobnie najłatwiejszy do zrozumienia dla początkujących.

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
BabarBaig
źródło
0

W przypadku prostego ciągu z ograniczeniem spacji użycie Dict byłoby dość szybkie, zobacz poniższy kod

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')
Amit Gowda
źródło
0

Możesz użyć startswithmetody:

def count_substring(string, sub_string):
    x = 0
    for i in range(len(string)):
        if string[i:].startswith(sub_string):
            x += 1
    return x
Trevor Maseleme
źródło
0

Poniższa logika będzie działać dla wszystkich ciągów znaków i znaków specjalnych

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"))
skay
źródło
0

Oto rozwiązanie w Pythonie 3 i bez rozróżniania wielkości liter:

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)
attachPost
źródło
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
vengat
źródło
2
Chociaż wszystkie odpowiedzi są mile widziane, odpowiedzi tylko w kodzie zwykle nie wyjaśniają tematu bardzo dobrze. Dodaj kontekst.
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)
pawan kumar
źródło
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))
pawan kumar
źródło
0

To tworzy listę wszystkich wystąpień (również nakładających się) w ciągu i zlicza je

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

Przykład:

str1 ='abcabcd'
str2 = 'bc'

utworzy tę listę, ale zapisz tylko wartości BOLD :

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

to zwróci:

len([bc, bc])
Elad L.
źródło
1
Proszę zastanowić się nad dodaniem przynajmniej niektórych wyjaśnień, jakby to dlaczego odpowiadało na pytanie
β.εηοιτ.βε
0

Oto rozwiązanie, które działa zarówno w przypadku nakładających się, jak i nakładających się zdarzeń. Dla wyjaśnienia: nakładający się podciąg to taki, którego ostatni znak jest identyczny z pierwszym znakiem.

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
mrs-qv7
źródło