Bir dizedeki belirli bir alt dizenin yineleme sayısını sayma


205

Python'daki bir dize içinde belirli bir alt dizenin kaç kez bulunduğunu nasıl sayabilirim?

Örneğin:

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

"Alt dize sayısı" ile ne demek istiyorsun? Alt dize konumu? Alt dize kaç kez oluşur? Başka bir şey?
GreenMatt

2
Bu bir ödev mi? Öyleyse, lütfen sorunuza "ödev" etiketini ekleyin. Ayrıca, sorunuz çok net değil. Sorduğun soruya cevap vereceğim, ama sanırım gerçekten başka bir şey bulmak istiyorsun.
Jim DeLaHunt

Önceki açıklamanın ardından şunu görmek isteyebilirsiniz: python: Başka bir dizede bir alt dize nasıl bulunur veya dize (python) içindeki bir alt dizenin Temel dizin oluşturma yinelemeleri . Bu muhtemelen bunlardan birinin kopyası gibi göründüğü için, kapatmaya oy veriyorum.
GreenMatt

@JimDeLaHunt Kayıtlar için, bu konuda cscircles.cemc.uwaterloo.ca/8-remix'te bir alıştırma var - bkz. Kodlama Alıştırması: Alt Dize Sayımı .
Nikos Alexandris

Yanıtlar:


335

string.count(substring), gibi:

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

Güncelleme:

Yorumlarda belirtildiği gibi, örtüşmeyen olaylar için bunu yapmanın yolu budur . Çakışan olayları saymanız gerekiyorsa, şu yanıtları kontrol etseniz iyi olur: " Python regex çakışan tüm eşleşmeleri buluyor mu? " Veya aşağıdaki diğer cevabımı kontrol et.


14
Peki ya: "GCAAAAAG".count("AAA")1 verir, doğru cevap 3'tür?
karikatürist

12
countaçıkça üst üste gelmeyen maçlar içindir - ki çoğu zaman bir şey yapmak ister. stackoverflow.com/questions/5616822/… Çakışan eşleşmelerle ilgileniyor - ancak sum("GCAAAAAGH"[i:].startswith("AAA") for i in range(len("GCAAAAAGH")))
pahalıysa

Aynı anda birden fazla kelimeyi saymak / aramak mümkün müdür? like string.count (substring1, substring2)
Sushant Kulkarni

@SushantKulkarni sayılı rağmen böyle bir şeyi yapmanın bir mantıksal yol var: string.count(substring1) + string.count(substring2). Ancak, çok sayıda alt dize varsa bunun etkili bir yöntem olmadığını unutmayın, çünkü her bir alt dizeyi saymak ana dize üzerinde bir yineleme gerektirir.
Faheel

@SushantKulkarni yapmak ''.join([substring1, substring2]).count(pattern)yukarıda önerilen çözümden daha verimlidir. Timeit kullanarak kontrol ettim.
Enric Calabuig

24
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
Ek açıklamalar cevabınızı geliştirecektir.
ryanyuyu

19

Gerçekten ne demek istediğinize bağlı olarak, aşağıdaki çözümleri öneriyorum:

  1. Boşluklarla ayrılmış alt dizelerin bir listesini kastediyorsunuz ve tüm alt dizeler arasındaki alt dizgi konum numarasının ne olduğunu bilmek istiyorsunuz:

    s = 'sub1 sub2 sub3'
    s.split().index('sub2')
    >>> 1
  2. Dizedeki alt dizenin karakter konumunu kastediyorsunuz:

    s.find('sub2')
    >>> 5
  3. Bir su-bstring'in (örtüşmeyen) görünüm sayılarını kastediyorsunuz:

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

'Sub' veya 'su' bulmaya çalışın
obohovyk

Sanırım demek istiyorsun s.find("su")ve neden aldığını merak ediyorsun 0? Eh bu alt dizenin ilk endeksidir "su"içinde s. Deneyin "ub"ve alacaksınız 1, örneğin deneyin "z"ve -1hiçbir alt dize bulunamadı gibi alacaksınız .
Don Question

Yani her zaman sadece ilk dizini buluyorsunuz, ancak tüm dizinleri değil, @ arun-kumar-khattri doğru cevabı verdi
obohovyk

@ Arun-kumar-khattri'nin aradığınız "doğru" yanıtı verdiği için rahatladım. Belki de jsbueno'nun yorumlarına ek olarak bakmalısınız, bazen henüz sormadığınız soruları cevaplarlar.
Don Question

Üçüncü yaklaşım gibi. BTW, bence çakışan olmayan durumlarda işe yaradığını belirtmelisiniz.
Zeinab Abbasimazar

12

Belirli bir dizede üst üste binen alt dizeyi bulmanın en iyi yolu, normal ifade kitaplığını kullanarak üst üste binen tüm eşleşmeyi bulacağı python düzenli ifadesini kullanmaktır. İşte bunu nasıl yapacağınız alt dize ve sağda dizeyi eşleştirmek için

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

2
belki alt dizeyi dinamik olarak eklemek için len (re.findall (f '(? = {sub_string})', 'caaaab')) ekleyebilirsiniz :)
Amresh Giri

10

Python 3'te bir dizede bir alt dizenin çakışan oluşumlarını bulmak için, bu algoritma şunları yapar:

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  

Bu algoritmayı kendim kontrol ettim ve işe yaradı.


1
Küçük ipucu: "Bunu kontrol ettiğim için çalışır" demek yerine, repl.it gibi bir çevrimiçi hizmete bazı örnek verilerle bir örnek ekleyebilirsiniz .
Valentin

1
yorumunuz için teşekkür ederim Valentin! Bu benim ilk cevabım. Bir sonraki cevaplarımdan kendimi geliştireceğim.
Bharath Kumar R

10

Frekansı iki yolla sayabilirsiniz:

  1. Kullanılması count()in str:

    a.count(b)

  2. Veya şunları kullanabilirsiniz:

    len(a.split(b))-1

aDize ve bfrekansı hesaplanacak alt dize nerede .


7

Mevcut en iyi yanıt yöntemi count, örtüşen olayları saymaz ve boş alt dizeleri de umursamaz. Örneğin:

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

İlk cevap olmalıdır 2değil 1biz örtüşen alt dizeleri göz önüne alırsak,. İkinci cevaba gelince, boş bir alt dizginin asnwer olarak 0 döndürmesi daha iyidir.

Aşağıdaki kod bu şeylerle ilgilenir.

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

Şimdi çalıştırdığımızda:

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

6

Senaryo 1: Bir cümlede bir kelimenin oluşması. örneğin: str1 = "This is an example and is easy". "İs" kelimesinin oluşumu. Haydistr2 = "is"

count = str1.count(str2)

Senaryo 2: Cümlenin içinde kalıp oluşumu.

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

Teşekkürler!


(string [j] == sub_string [0]) ise bu denetime gerçekten ihtiyacımız var mı? sonraki durumda otomatik olarak kapsanmaz mı?
AnandViswanathan89

AnandViswanathan89, Her iki koşul da gerekiyorsa, (string [j] == sub_string [0]), ana dizenin tüm karakterleri için gerçekleştirilmesi gereken ana dize içindeki ilk karakter eşleşmesini kontrol ederse ve (string [ j: j + len2] == sub_string) alt dize oluşumunu gerçekleştirir. İlk olay içinse, ikincisi koşulun yeterli olması durumunda.
Nisan

4

Soru çok net değil, ama yüzeyde ne olduğunu sordum.

L karakter uzunluğunda ve S [1] dizenin ilk karakteri ve S [L] son ​​karakter olduğunda S dizesi aşağıdaki alt dizelere sahiptir:

  • Boş dize ''. Bunlardan biri var.
  • A'dan L'ye her A değeri için, A'dan L'ye her B değeri için S [A] .. S [B] (dahil). Bu dizelerden L + L-1 + L-2 + ... 1, toplam 0.5 * L * (L + 1) için vardır.
  • İkinci öğenin S [1] .. S [L], yani orijinal S dizesinin tamamını içerdiğini unutmayın.

Bu nedenle, L uzunluğunda bir dizede 0,5 * L * (L + 1) + 1 alt dizesi vardır.


4

Bunun bir yolu kullanmaktır re.subn. Örneğin, 'hello'herhangi bir vaka karışımındaki olay sayısını saymak için şunları yapabilirsiniz:

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

Benim için kelime, teşekkürler. @santosh, neden cevap kabul etmiyorsun?
Mawg, Monica'ya

2

Kabul edilen cevabımı "bunu yapmanın basit ve açık bir yolu" olarak tutacağım - ancak bu örtüşen olayları kapsamaz. Bunları bulmak dilimler çoklu kontrol ile saf olarak yapılabilir - olduğu gibi: sum ("GCAAAAAGH" [i:]. Aralıktaki i için (len ("GCAAAAAGH")) başlar ("AAA")

(Bu 3 verir) - Python regex tüm örtüşen maçlar bulmak gibi düzenli ifadeler hile kullanımı ile yapılabilir ? - ve aynı zamanda ince kod golf yapmak için yapabilir - Bu benim "el yapımı" sayım son derece naif değil çalışır bir dizede üst üste gelen desen için (en azından her etkileşim yeni dize nesneleri oluşturmaz):

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

Çakışan olaylar:

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

Sonuçlar:

my maaather lies over the oceaaan
6
4
2

2

Çakışan sayım için kullanımı kullanabiliriz:

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

Çakışan olmayan durumlarda count () işlevini kullanabiliriz:

string.count(sub_string)

2

Liste kavrayışı olan bir astardan ne haber? Teknik olarak 93 karakter uzunluğunda, bana PEP-8 saflığını koruyor. Regex.findall cevabı, yüksek düzeyde bir kod parçası ise en okunabilir cevaptır. Düşük bir şey inşa ediyorsanız ve bağımlılıklar istemiyorsanız, bu oldukça yalın ve anlamlıdır. Çakışan cevabı veriyorum. Açıkçası, çakışma yoksa sayıyı en yüksek puan yanıtı gibi kullanın.

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

Tüm alt dizeyi (üst üste binenler dahil) saymak istiyorsanız, bu yöntemi kullanın.

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

1

Herhangi bir dizenin içindeki alt dize sayısını öğrenmek istiyorsanız; lütfen aşağıdaki kodu kullanın. Kodu anlamak kolay bu yüzden yorumları atladı. :)

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

Bunun bir şeye bakıp bakmadığından emin değilim, ama bunu 'tek kullanımlık' bir kelimeye çözüm olarak düşündüm:

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

print count

Nerede kelime kelime içeri arıyorsunuz ve terim Aradığınız terimdir


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
Belki de bu çözümün diğerinden nasıl farklı olduğunu açıklayabilirsiniz, çözebileceği özel bir durum var mı?
mpaskov

2
Bu kod soruyu cevaplayabilirken, sorunun nasıl ve / veya neden çözüldüğüne dair ek bağlam sağlamak yanıtlayıcının uzun vadeli değerini artıracaktır.
Donald Duck

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

Bu, dizede alt dizenin kaç kez bulunduğunu bulur ve dizini görüntüler.


import re d = [m.start (), re.finditer'deki m (st3, st2)] # dizede bulunan alt dizenin sayısını ve görüntüleme dizinini yazdırma sayısını görüntüler (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

2'den fazla kişi bu çözümü zaten sağladığından bir aşağı oyu tehlikeye atmak Hatta onlardan birini bile iptal ettim. Ama benimki yeni başlayanlar için muhtemelen en kolay olanıdır.

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

Alan sınırlamalı basit bir dize için Dict kullanmak oldukça hızlı olur, lütfen aşağıdaki koda bakın

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

startswithYöntemi kullanabilirsiniz :

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şağıdaki mantık tüm dize ve özel karakterler için çalışacaktır

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

İşte Python 3'teki çözüm ve büyük / küçük harf duyarsız:

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
Tüm cevaplar takdir edilirken, sadece kod cevapları konuyu çok iyi açıklama eğilimindedir. Lütfen bir bağlam ekleyin.
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

Bu, dizedeki tüm oluşumların (ayrıca çakışan) bir listesini yapar ve bunları sayar

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

Misal:

str1 ='abcabcd'
str2 = 'bc'

bu listeyi oluşturur, ancak yalnızca BOLD değerlerini kaydeder :

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

geri dönecek:

len([bc, bc])

1
Lütfen neden bu soruyu cevaplıyormuş gibi en azından biraz açıklama eklemeyi düşünün
βε.εηοιτ.βε

0

Üst üste binmeyen ve çakışan olaylar için çalışan bir çözüm. Açıklığa kavuşturmak için: örtüşen bir alt dize, son karakteri ilk karakterine özdeş olan alt dizedir.

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.