นับจำนวนครั้งของสตริงย่อยที่กำหนดในสตริง


205

ฉันจะนับจำนวนครั้งที่มีซับสตริงที่ระบุอยู่ภายในสตริงใน Python ได้อย่างไร

ตัวอย่างเช่น:

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

คุณหมายถึงอะไรโดย "จำนวนสตริงย่อย"? ตำแหน่งของสตริงย่อย? สตริงย่อยเกิดขึ้นกี่ครั้ง อื่น ๆ อีก?
GreenMatt

2
นี่เป็นการบ้านหรือเปล่า? ถ้าเป็นเช่นนั้นโปรดเพิ่มแท็ก "การบ้าน" ในคำถามของคุณ คำถามของคุณยังไม่ชัดเจน ฉันจะตอบสิ่งที่คุณดูเหมือนจะถาม แต่ฉันสงสัยว่าคุณต้องการค้นหาอย่างอื่น
Jim DeLaHunt

ต่อไปนี้ความคิดเห็นก่อนหน้าคุณอาจต้องการที่จะดู: หลาม: วิธีการหาย่อยในสายอื่นหรือกลับเป็นซ้ำของการจัดทำดัชนีพื้นฐานย่อยภายในสตริง (งูใหญ่) เนื่องจากนี่น่าจะเป็นสิ่งที่ซ้ำซ้อนอย่างหนึ่งฉันจึงลงคะแนนให้ปิด
GreenMatt

@JimDeLaHunt สำหรับบันทึกที่มีการออกกำลังกายเกี่ยวกับเรื่องนี้ในcscircles.cemc.uwaterloo.ca/8-remix - ดูการเข้ารหัสการใช้สิทธิ: สตริงย่อยนับ
Nikos Alexandris

คำตอบ:


335

string.count(substring), ชอบใน:

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

ปรับปรุง:

ตามที่ระบุไว้ในความคิดเห็นนี้เป็นวิธีการทำสำหรับเหตุการณ์ที่ไม่ทับซ้อนกัน หากคุณต้องการนับเหตุการณ์ที่ทับซ้อนกันคุณควรตรวจสอบคำตอบที่: " Python regex ค้นหาการจับคู่ที่ซ้อนกันทั้งหมดหรือไม่ " หรือเพียงตรวจสอบคำตอบอื่น ๆ ของฉันด้านล่าง


14
เกี่ยวกับสิ่งนี้: "GCAAAAAG".count("AAA")ซึ่งให้ 1 ในขณะที่คำตอบที่ถูกต้องคือ 3
นักเขียนการ์ตูน

12
countเห็นได้ชัดสำหรับการจับคู่ที่ไม่ทับซ้อนกัน - ซึ่งส่วนใหญ่มักจะเป็นสิ่งที่คนต้องการทำ stackoverflow.com/questions/5616822/…จัดการกับการจับคู่ที่ทับซ้อนกัน - แต่การแสดงออกที่เรียบง่ายถ้าราคาแพงคือ:sum("GCAAAAAGH"[i:].startswith("AAA") for i in range(len("GCAAAAAGH")))
jsbueno

เป็นไปได้ไหมที่จะนับ / ค้นหาคำหลายคำพร้อมกัน? ชอบ string.count (substring1, substring2)
Sushant Kulkarni

@SushantKulkarni string.count(substring1) + string.count(substring2)เลขที่แม้ว่าจะมีเป็นหนึ่งในทางตรรกะของการทำสิ่งดังกล่าว แต่โปรดจำไว้ว่านี่ไม่ใช่วิธีที่มีประสิทธิภาพหากมีสตริงย่อยมากมายเนื่องจากการนับสตริงย่อยแต่ละรายการต้องการการวนซ้ำมากกว่าสตริงหลัก
Faheel

@SushantKulkarni การทำ''.join([substring1, substring2]).count(pattern)มีประสิทธิภาพมากกว่าโซลูชั่นที่แนะนำข้างต้น ฉันตรวจสอบโดยใช้ timeit
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
คำอธิบายเพิ่มเติมจะช่วยปรับปรุงคำตอบของคุณ
ryanyuyu

19

ฉันขอเสนอวิธีแก้ปัญหาดังต่อไปนี้:

  1. คุณหมายถึงรายการของช่องว่างย่อยสตริงย่อยและต้องการที่จะรู้ว่าสิ่งที่เป็นจำนวนตำแหน่งสตริงย่อยในทุกสตริงย่อย:

    s = 'sub1 sub2 sub3'
    s.split().index('sub2')
    >>> 1
  2. คุณหมายถึงตำแหน่งถ่านของสตริงย่อยในสตริง:

    s.find('sub2')
    >>> 5
  3. คุณหมายถึง (ไม่ทับซ้อนกัน) นับจากลักษณะของ SU-bstring:

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

ลองค้นหา 'sub' หรือ 'su'
obohovyk

ฉันเดาว่าคุณหมายถึงs.find("su")และสงสัยว่าทำไมคุณได้รับ0? อย่างนี้เป็นดัชนีแรกของสตริงย่อยใน"su" sลอง"ub"และคุณจะได้รับ1ลองเช่น"z"และคุณจะได้รับ-1ในไม่พบสตริงย่อย
อย่าตอบคำถาม

ฉันหมายความว่าคุณมักจะพบดัชนีแรกเท่านั้น แต่ไม่ได้ดัชนีทั้งหมด @ อรุณ kumar-khattri gived ที่ถูกต้องคำตอบ
obohovyk

ฉันรู้สึกโล่งใจที่ @ arun-kumar-khattri ให้คำตอบที่ "ถูกต้อง" ที่คุณต้องการ บางทีคุณควรดูความคิดเห็นของ jsbueno เพิ่มเติมบางครั้งพวกเขาตอบคำถามที่คุณยังไม่ได้ถาม
อย่าตั้งคำถาม

ชอบวิธีที่สาม BTW ฉันคิดว่าคุณควรพูดถึงว่ามันใช้งานได้กับกรณีที่ไม่ทับซ้อนกัน
Zeinab Abbasimazar

12

วิธีที่ดีที่สุดในการค้นหาสตริงย่อยที่ทับซ้อนกันในสตริงที่กำหนดคือการใช้นิพจน์ทั่วไปของไพ ธ อนมันจะค้นหาการจับคู่ที่ทับซ้อนกันทั้งหมดโดยใช้ไลบรารีนิพจน์ทั่วไป นี่คือวิธีการทำซ้ายคือซับสตริงและในขวาคุณจะให้สตริงเพื่อให้ตรงกับ

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

2
บางทีคุณสามารถเพิ่ม len (re.findall (f '(? = {sub_string})', 'caaaab')) เพื่อแทรกสตริงย่อยแบบไดนามิก :)
Amresh Giri

10

ในการค้นหาการทับซ้อนของสตริงย่อยในสตริงใน Python 3 อัลกอริทึมนี้จะทำ:

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  

ฉันเองตรวจสอบอัลกอริทึมนี้และใช้งานได้


1
เคล็ดลับเล็ก ๆ : แทนที่จะพูดว่า "ใช้งานได้เพราะฉันตรวจสอบแล้ว" คุณสามารถใส่ตัวอย่างบนบริการออนไลน์เช่นrepl.itกับข้อมูลตัวอย่างบางส่วนได้
Valentin

1
ขอบคุณสำหรับความคิดเห็นของคุณ Valentin! มันเป็นคำตอบแรกของฉันที่นี่ ฉันจะปรับปรุงตัวเองจากคำตอบต่อไปของฉัน
Bharath Kumar R

10

คุณสามารถนับความถี่ได้สองวิธี:

  1. ใช้count()ในstr:

    a.count(b)

  2. หรือคุณสามารถใช้:

    len(a.split(b))-1

aสตริงอยู่ที่ไหนและbเป็นสตริงย่อยที่ต้องคำนวณความถี่


7

คำตอบที่ดีที่สุดในปัจจุบันที่เกี่ยวข้องกับวิธีการcountไม่นับการทับซ้อนที่เกิดขึ้นจริง ๆ และไม่สนใจซับสตริงว่างเช่นกัน ตัวอย่างเช่น:

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

คำตอบแรกที่ควรจะ2ไม่ได้1ถ้าเราพิจารณาสตริงที่ทับซ้อนกัน สำหรับคำตอบที่สองจะดีกว่าถ้าสตริงย่อยว่างส่งคืน 0 เป็น asnwer

รหัสต่อไปนี้จะดูแลสิ่งเหล่านี้

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

ตอนนี้เมื่อเรารันมัน:

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

6

สถานการณ์ที่ 1: การเกิดขึ้นของคำในประโยค str1 = "This is an example and is easy"เช่น: การเกิดขึ้นของคำว่า "คือ" ช่วยให้str2 = "is"

count = str1.count(str2)

สถานการณ์ที่ 2: การเกิดขึ้นของรูปแบบในประโยค

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

ขอบคุณ!


เราต้องการการตรวจสอบนี้จริง ๆ หรือไม่ (string [j] == sub_string [0]): มันจะไม่ครอบคลุมโดยอัตโนมัติหากเกิดเงื่อนไขหรือไม่
AnandViswanathan89

AnandViswanathan89, ทั้งสองถ้าเงื่อนไขเป็นสิ่งจำเป็น, ถ้า (string [j] == sub_string [0]) ตรวจสอบการจับคู่อักขระเริ่มต้นภายในสายหลักซึ่งจะต้องดำเนินการสำหรับตัวละครทั้งหมดของสายหลักและถ้า (สตริง [ j: j + len2] == sub_string) ทำการซับสตริงที่เกิดขึ้น หากเป็นครั้งแรกที่เกิดขึ้นแล้วที่สองหากเงื่อนไขจะพอเพียง
Amith VV

4

คำถามไม่ชัดเจน แต่ฉันจะตอบสิ่งที่คุณถาม

สตริง S ซึ่งมีความยาวอักขระ L และที่ S [1] เป็นอักขระตัวแรกของสตริงและ S [L] เป็นอักขระตัวสุดท้ายมีสตริงย่อยดังต่อไปนี้:

  • สตริง null '' มีหนึ่งในสิ่งเหล่านี้
  • สำหรับทุกค่า A จาก 1 ถึง L สำหรับทุกค่า B จาก A ถึง L สตริง S [A] .. S [B] (รวม) มี L + L-1 + L-2 + ... 1 ของสตริงเหล่านี้รวม 0.5 * L * (L + 1)
  • โปรดทราบว่ารายการที่สองประกอบด้วย S [1] .. S [L] คือสตริงต้นฉบับทั้งหมด S

ดังนั้นจึงมีสตริงย่อย 0.5 * L * (L + 1) + 1 ภายในสตริงที่มีความยาว L. Render นิพจน์ดังกล่าวใน Python และคุณมีจำนวนสตริงย่อยอยู่ภายในสตริง


4

re.subnวิธีหนึ่งคือการใช้งาน ตัวอย่างเช่นหากต้องการนับจำนวนที่เกิดขึ้น'hello'ในกรณีใด ๆ ก็ตามที่คุณสามารถทำได้

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

คำสำหรับฉันขอบคุณ @santosh ทำไมไม่ยอมรับคำตอบ?
Mawg พูดว่าคืนสถานะโมนิก้า

2

ฉันจะเก็บคำตอบที่ยอมรับว่าเป็น "วิธีที่ง่ายและชัดเจนในการทำ" - อย่างไรก็ตามนั่นไม่ครอบคลุมถึงเหตุการณ์ที่เกิดขึ้นซ้ำซ้อน การค้นหาสิ่งเหล่านั้นสามารถทำได้อย่างไร้เดียงสาโดยมีการตรวจสอบหลายส่วน - เช่นใน: sum ("GCAAAAAGH" [i:]. startswith ("AAA") สำหรับ i ในช่วง (len ("GCAAAAAGH"))

(ซึ่งให้ผลตอบแทน 3) - สามารถทำได้โดยใช้เคล็ดลับในการใช้นิพจน์ทั่วไปอย่างที่เห็นได้จากPython regex พบการแข่งขันที่ทับซ้อนกันทั้งหมดหรือไม่ - และมันยังสามารถทำเพื่อการตีกอล์ฟแบบละเอียดได้ - นี่คือการนับ "แฮนด์เมด" ของฉันสำหรับการทับซ้อนของรูปแบบในสตริงซึ่งพยายามที่จะไม่ไร้เดียงสาอย่างมาก (อย่างน้อยก็ไม่ได้สร้างวัตถุสตริงใหม่ในการโต้ตอบแต่ละครั้ง):

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

เหตุการณ์ที่ทับซ้อนกัน:

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

ผล:

my maaather lies over the oceaaan
6
4
2

2

สำหรับการนับที่ทับซ้อนกันเราสามารถใช้:

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

สำหรับกรณีที่ไม่ทับซ้อนกันเราสามารถใช้ฟังก์ชัน count ():

string.count(sub_string)

2

วิธีการเกี่ยวกับหนึ่งซับกับรายการความเข้าใจ? ในทางเทคนิคแล้วมันมีความยาว 93 ตัวอักษรทำให้ฉันพิถีพิถันในการใช้ PEP-8 คำตอบ regex.findall สามารถอ่านได้มากที่สุดหากเป็นโค้ดระดับสูง หากคุณกำลังสร้างบางสิ่งบางอย่างในระดับต่ำและไม่ต้องการการพึ่งพาสิ่งนี้จะค่อนข้างเอนเอียงและหมายถึง ฉันให้คำตอบที่ทับซ้อนกัน เห็นได้ชัดว่าใช้นับเช่นคำตอบคะแนนสูงสุดหากไม่มีการทับซ้อนกัน

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

หากคุณต้องการนับสตริงย่อยทั้งหมด (รวมถึงที่ทับซ้อนกัน) ให้ใช้วิธีนี้

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

1

หากคุณต้องการทราบจำนวนของสตริงย่อยภายในสตริงใด ๆ กรุณาใช้รหัสด้านล่าง รหัสเข้าใจง่ายนั่นคือเหตุผลที่ฉันข้ามความคิดเห็น :)

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

ฉันไม่แน่ใจว่านี่เป็นสิ่งที่ดูแล้ว แต่ฉันคิดว่านี่เป็นวิธีแก้ปัญหาสำหรับคำที่ 'ใช้แล้วทิ้ง':

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

print count

โดยที่คำคือคำที่คุณกำลังค้นหาและคำนั้นเป็นคำที่คุณกำลังค้นหา


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
บางทีคุณสามารถอธิบายอย่างละเอียดถึงวิธีการแก้ปัญหานี้แตกต่างจากที่อื่น ๆ มีกรณีพิเศษที่สามารถแก้ไขได้หรือไม่?
mpaskov

2
ในขณะที่รหัสนี้อาจตอบคำถามให้บริบทเพิ่มเติมเกี่ยวกับวิธีการและ / หรือทำไมมันแก้ปัญหาจะปรับปรุงค่าระยะยาวของคำตอบ
Donald Duck

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

พบจำนวนครั้งสตริงย่อยที่พบในสตริงและแสดงดัชนี


import re d = [m.start () สำหรับ m ใน re.finditer (st3, st2)] # พบจำนวนครั้งที่สตริงย่อยที่พบในสตริงและพิมพ์ดัชนีการแสดงผล (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

เสี่ยงต่อการ downvote เนื่องจากมีอีก 2 คนที่ได้ให้โซลูชันนี้แล้ว ฉันยังลงคะแนนหนึ่งในนั้น แต่ของฉันน่าจะง่ายที่สุดสำหรับมือใหม่ที่จะเข้าใจ

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

สำหรับสตริงอย่างง่ายที่มีการเว้นวรรคการใช้ Dict ค่อนข้างเร็วโปรดดูรหัสด้านล่าง

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

ตรรกะด้านล่างจะใช้ได้กับสตริงและอักขระพิเศษทั้งหมด

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

นี่คือวิธีแก้ปัญหาใน Python 3 และตัวพิมพ์เล็กและตัวพิมพ์ใหญ่:

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
ในขณะที่คำตอบทั้งหมดได้รับการชื่นชม แต่รหัสคำตอบเท่านั้นมักจะไม่อธิบายเรื่องที่ดีมาก โปรดเพิ่มบริบท
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

สิ่งนี้ทำให้รายการสิ่งที่เกิดขึ้นทั้งหมด (เช่นการทับซ้อนกัน) ในสตริงและนับมัน

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

ตัวอย่าง:

str1 ='abcabcd'
str2 = 'bc'

จะสร้างรายการนี้ แต่บันทึกเฉพาะค่าBOLD :

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

ที่จะกลับมา:

len([bc, bc])

1
โปรดลองเพิ่มคำอธิบายอย่างน้อยราวกับว่าทำไมนี่ถึงตอบคำถาม
β.εηοιτ.βε

0

ต่อไปนี้เป็นโซลูชันที่ใช้งานได้กับทั้งการเกิดที่ไม่ซ้ำซ้อนและการทับซ้อนกัน ในการชี้แจง: สตริงย่อยที่ทับซ้อนกันเป็นอักขระที่มีอักขระตัวสุดท้ายเหมือนกับอักขระตัวแรก

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.