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

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.


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

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

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

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ł.


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ć.


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

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!


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.


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

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

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

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)

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

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

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

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


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
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.


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)

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

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

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

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

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)

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

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

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

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.