255

How can I count the number of times a given substring is present within a string in Python?

For example:

>>> 'foo bar foo'.numberOfOccurrences('foo')
2
jsbueno
  • 86,446
  • 9
  • 131
  • 182
santosh
  • 3,456
  • 3
  • 20
  • 28
  • What do you mean by "number of substring"? The position of the substring? How many times the substring occurs? Something else? – GreenMatt Jan 17 '12 at 18:44
  • 2
    Is this a homework assignment? If so, please add the tag "homework" to your question. Also, your question isn't very clear. I'll answer what you seem to be asking, but I suspect you really want to find out something else. – Jim DeLaHunt Jan 17 '12 at 18:45
  • Following previous comment, you might want to see: [python: How to find a substring in another string](http://stackoverflow.com/questions/7361253/python-how-to-find-a-substring-in-another-string) or [Basic indexing recurrences of a substring within a string (python)](http://stackoverflow.com/questions/6987702/basic-indexing-recurrences-of-a-substring-within-a-string-python). As this seems a likely duplicate of one of those, I'm voting to close. – GreenMatt Jan 17 '12 at 18:51
  • @JimDeLaHunt For the records, there is an exercise about this in http://cscircles.cemc.uwaterloo.ca/8-remix/ -- see _Coding Exercise: Substring Counting_. – Nikos Alexandris Jun 05 '13 at 15:08
  • Interesting in the exercise found at cscircles.cemc.uwaterloo.ca/8-remix is that what is asked for is how many times a substring appears no matter if its occurrences overlap. – Nikos Alexandris Jun 05 '13 at 15:12
  • 2
    Possible duplicate of [Basic indexing recurrences of a substring within a string (python)](https://stackoverflow.com/questions/6987702/basic-indexing-recurrences-of-a-substring-within-a-string-python) – Valentin Jul 15 '17 at 15:43

35 Answers35

409

string.count(substring), like in:

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

Update:

As pointed up in the comments, this is the way to do it for non overlapping occurrences. If you need to count overlapping occurrences, you'd better check the answers at: "Python regex find all overlapping matches?", or just check my other answer below.

Trenton McKinney
  • 43,885
  • 25
  • 111
  • 113
jsbueno
  • 86,446
  • 9
  • 131
  • 182
  • 21
    What about this: `"GCAAAAAG".count("AAA")` which gives 1, while the correct answer is 3? – cartoonist May 09 '15 at 15:52
  • 20
    `count` is obviously for non-overlapping matches - which is most often what one wants to do. http://stackoverflow.com/questions/5616822/python-regex-find-all-overlapping-matches deals with overlapping matches - but a simple, if expensive, expression is: `sum("GCAAAAAGH"[i:].startswith("AAA") for i in range(len("GCAAAAAGH")))` – jsbueno Jun 26 '15 at 14:08
  • Is it possible to count/search multiple words at once? like string.count(substring1, substring2) – Sushant Kulkarni Mar 15 '17 at 02:47
  • @SushantKulkarni No. Though there's one logical way of doing such a thing: `string.count(substring1) + string.count(substring2)`. But keep in mind that this is not an efficient method if there are a lot of substrings because counting each substring requires an iteration over the main string. – Faheel Nov 22 '17 at 18:15
  • @SushantKulkarni doing `''.join([substring1, substring2]).count(pattern)` is more efficient than the solution suggested above. I checked using timeit. – Enric Calabuig Jan 15 '18 at 14:48
  • In little tricky cases like "ABCDCDC".count("CDC") it will fail. – CoDe Jul 31 '18 at 08:42
  • Would it be possible to get a `regex` pattern into `count()`? – gies0r Jun 12 '20 at 15:18
  • For a regex, use `len(re.findall(, ))` - you have to do `import re` first to get the regexp module, of course. – jsbueno Jun 12 '20 at 15:22
33
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
  • 1,361
  • 14
  • 21
20

Depending what you really mean, I propose the following solutions:

  1. You mean a list of space separated sub-strings and want to know what is the sub-string position number among all sub-strings:

    s = 'sub1 sub2 sub3'
    s.split().index('sub2')
    >>> 1
    
  2. You mean the char-position of the sub-string in the string:

    s.find('sub2')
    >>> 5
    
  3. You mean the (non-overlapping) counts of appearance of a su-bstring:

    s.count('sub2')
    >>> 1
    s.count('sub')
    >>> 3
    
kalehmann
  • 4,449
  • 6
  • 23
  • 35
Don Question
  • 10,678
  • 5
  • 33
  • 50
  • Try to find 'sub' or 'su' – obohovyk Jan 25 '17 at 17:45
  • I guess you mean `s.find("su")` and wonder why you get `0`? Well this is the first index of the sub-string `"su"` in `s`. Try `"ub"` and you will get `1`, try e.g. `"z"` and you will get `-1` as in no substring found. – Don Question Jan 25 '17 at 18:33
  • I mean you always find only first index, but not all indexes, @arun-kumar-khattri gived correct answer – obohovyk Jan 25 '17 at 22:03
  • I'm relieved that @arun-kumar-khattri gave the "correct" answer you were looking for. Maybe you should take an additional look at jsbueno's comments, sometimes they answer questions you just haven't asked yet. – Don Question Jan 26 '17 at 02:27
  • Like for the third approach. BTW, I think you should mention that it works for non-overlapping cases. – Zeinab Abbasimazar Sep 06 '17 at 11:03
15

The best way to find overlapping sub-string in a given string is to use the python regular expression it will find all the overlapping matching using the regular expression library. Here is how to do it left is the substring and in right you will provide the string to match

print len(re.findall('(?=aa)','caaaab'))
3
Deepak Yadav
  • 594
  • 6
  • 14
12

To find overlapping occurences of a substring in a string in Python 3, this algorithm will do:

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  

I myself checked this algorithm and it worked.

Bharath Kumar R
  • 133
  • 2
  • 6
  • 2
    Small tip: Instead of saying "It works because I checked it", you could include an example on an online service like https://repl.it with some sample data. – Valentin Jul 15 '17 at 15:48
  • 2
    thank you for your comment Valentin! It's my first answer here. I will improve myself from my next answers. – Bharath Kumar R Jul 15 '17 at 17:18
11

You can count the frequency using two ways:

  1. Using the count() in str:

    a.count(b)

  2. Or, you can use:

    len(a.split(b))-1

Where a is the string and b is the substring whose frequency is to be calculated.

Green
  • 2,212
  • 2
  • 21
  • 45
Anuj Gupta
  • 490
  • 4
  • 9
10

Scenario 1: Occurrence of a word in a sentence. eg: str1 = "This is an example and is easy". The occurrence of the word "is". lets str2 = "is"

count = str1.count(str2)

Scenario 2 : Occurrence of pattern in a sentence.

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

Thanks!

Aditya
  • 453
  • 3
  • 11
Amith V V
  • 101
  • 1
  • 2
  • do we really need this check if(string[j] == sub_string[0]): ? isn't it automatically covered in subsequent if condition? – AnandViswanathan89 Feb 13 '19 at 06:34
  • AnandViswanathan89,Both if conditions are required, if(string[j] == sub_string[0]) checks for the initial character match within the main string, which has to be performed for the entire characters of the main string and if(string[j:j+len2] == sub_string) performs the substring occurrence. If it is for the first occurrence then the second if the condition would have sufficed. – Amith V V Feb 14 '19 at 08:21
8

The current best answer involving method count doesn't really count for overlapping occurrences and doesn't care about empty sub-strings as well. For example:

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

The first answer should be 2 not 1, if we consider the overlapping substrings. As for the second answer it's better if an empty sub-string returns 0 as the asnwer.

The following code takes care of these things.

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

Now when we run it:

>>>num_of_patterns('caatatab', 'ata') #overlapping
2
>>>num_of_patterns('caatatab', '') #empty string
0
>>>num_of_patterns('abcdabcva','ab') #normal
2
Nuhman
  • 1,081
  • 16
  • 20
5

The question isn't very clear, but I'll answer what you are, on the surface, asking.

A string S, which is L characters long, and where S[1] is the first character of the string and S[L] is the last character, has the following substrings:

  • The null string ''. There is one of these.
  • For every value A from 1 to L, for every value B from A to L, the string S[A]..S[B] (inclusive). There are L + L-1 + L-2 + ... 1 of these strings, for a total of 0.5*L*(L+1).
  • Note that the second item includes S[1]..S[L], i.e. the entire original string S.

So, there are 0.5*L*(L+1) + 1 substrings within a string of length L. Render that expression in Python, and you have the number of substrings present within the string.

Jim DeLaHunt
  • 10,400
  • 3
  • 43
  • 71
4

One way is to use re.subn. For example, to count the number of occurrences of 'hello' in any mix of cases you can do:

import re
_, count = re.subn(r'hello', '', astring, flags=re.I)
print('Found', count, 'occurrences of "hello"')
Eugene Yarmash
  • 131,677
  • 37
  • 301
  • 358
4

If you want to count all the sub-string (including overlapped) then use this method.

import re
def count_substring(string, sub_string):
    regex = '(?='+sub_string+')'
    # print(regex)
    return len(re.findall(regex,string))
Rahul Verma
  • 2,532
  • 2
  • 10
  • 24
3

I will keep my accepted answer as the "simple and obvious way to do it" - however, that does not cover overlapping occurrences. Finding out those can be done naively, with multiple checking of the slices - as in: sum("GCAAAAAGH"[i:].startswith("AAA") for i in range(len("GCAAAAAGH")))

(which yields 3) - it can be done by trick use of regular expressions, as can be seen at Python regex find all overlapping matches? - and it can also make for fine code golfing - This is my "hand made" count for overlappingocurrences of patterns in a string which tries not to be extremely naive (at least it does not create new string objects at each interaction):

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))
Community
  • 1
  • 1
jsbueno
  • 86,446
  • 9
  • 131
  • 182
3

How about a one-liner with a list comprehension? Technically its 93 characters long, spare me PEP-8 purism. The regex.findall answer is the most readable if its a high level piece of code. If you're building something low level and don't want dependencies, this one is pretty lean and mean. I'm giving the overlapping answer. Obviously just use count like the highest score answer if there isn't overlap.

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
  • 931
  • 8
  • 18
2

Overlapping occurences:

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

Results:

my maaather lies over the oceaaan
6
4
2
SiHa
  • 6,756
  • 12
  • 30
  • 41
fyngyrz
  • 2,118
  • 2
  • 31
  • 42
2

For overlapping count we can use 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

For non-overlapping case we can use count() function:

string.count(sub_string)
2

Here's a solution that works for both non-overlapping and overlapping occurrences. To clarify: an overlapping substring is one whose last character is identical to its first character.

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
srm
  • 515
  • 1
  • 3
  • 15
  • _an overlapping substring is one whose last character is identical to its first character_ **and whose length is `> 1`** - otherwise `'a'`, for example, would be an overlapping substring. +1 for the clever thought though. – ack Jul 23 '21 at 17:29
  • After some more thinking I came to the conclusion that this definition (regarding the first and the last character) is wrong - consider the substring `laplap`. – ack Jul 24 '21 at 20:44
2

If you're looking for a power solution that works every case this function should work:

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

If you want to find out the count of substring inside any string; please use below code. The code is easy to understand that's why i skipped the comments. :)

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
  • 19
  • 1
1

Risking a downvote because 2+ others have already provided this solution. I even upvoted one of them. But mine is probably the easiest for newbies to understand.

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
Babar-Baig
  • 549
  • 1
  • 8
  • 22
1

You could use the startswith method:

def count_substring(string, sub_string):
    x = 0
    for i in range(len(string)):
        if string[i:].startswith(sub_string):
            x += 1
    return x
kalehmann
  • 4,449
  • 6
  • 23
  • 35
1
def count_substring(string, sub_string):
    inc = 0
    for i in range(0, len(string)):
        slice_object = slice(i,len(sub_string)+i)
        count = len(string[slice_object])
        if(count == len(sub_string)):
            if(sub_string == string[slice_object]):
                inc = inc + 1
    return inc

if __name__ == '__main__':
    string = input().strip()
    sub_string = input().strip()

    count = count_substring(string, sub_string)
    print(count)
sooraj ks
  • 11
  • 2
1
def count_substring(string, sub_string):
    k=len(string)
    m=len(sub_string)
    i=0
    l=0
    count=0
    while l<k:
        if string[l:l+m]==sub_string:
            count=count+1
        l=l+1
    return count

if __name__ == '__main__':
    string = input().strip()
    sub_string = input().strip()

    count = count_substring(string, sub_string)
    print(count)
Max Base
  • 605
  • 1
  • 7
  • 15
0

I'm not sure if this is something looked at already, but I thought of this as a solution for a word that is 'disposable':

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

print count

Where word is the word you are searching in and term is the term you are looking for

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
    Maybe you can elaborate on how this solution is different from the other, is there a special case that it is able to solve? – mpaskov Mar 07 '17 at 16:13
  • 2
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. – Donald Duck Mar 07 '17 at 18:50
0
import re
d = [m.start() for m in re.finditer(seaching, string)] 
print (d)

This finds the number of times sub string found in the string and displays index.

Omar Einea
  • 2,420
  • 6
  • 22
  • 35
  • import re d = [m.start() for m in re.finditer(st3, st2)] #finding the number of times sub string found in the string and display index print (d) – Bhaskar Reddi K Feb 13 '18 at 10:00
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

Below logic will work for all string & special characters

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"))
kalehmann
  • 4,449
  • 6
  • 23
  • 35
skay
  • 1
0

For a simple string with space delimitation, using Dict would be quite fast, please see the code as below

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

Here's the solution in Python 3 and case insensitive:

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
  • 55
  • 1
  • 1
  • 8
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
  • 1
  • 1
  • 1
  • 2
    While all answers are appreciated, code only answers tend to not explain the subject very good. Please add some context. – creyD Jul 24 '19 at 22:52
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

This makes a list of all the occurrences (also overlapping) in the string and counts them

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

Example:

str1 ='abcabcd'
str2 = 'bc'

will create this list but save only the BOLD values:

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

that will return:

len([bc, bc])
Elad L.
  • 599
  • 1
  • 8
  • 23
0
def count_substring(string, sub_string):
    counterList=[ 1 for i in range(len(string)-len(sub_string)+1) if string[i:i+len(sub_string)] == sub_string]
    count=sum(counterList)
    return count

if __name__ == '__main__':
    string = input().strip()
    sub_string = input().strip()

    count = count_substring(string, sub_string)
    print(count)
-6

If you're looking to count the whole string this can works.

stri_count="If you're looking to count the whole string this can works"
print(len(stri_count))
  • Hi Jean, and welcome to Stack Overflow! While this is interesting information, unfortunately it doesn't answer the question originally raised - please consider adding interesting information that is not a direct answer to the question asked as comments in the future. Further to this, `x.count('')` actually returns the length of the string + 1. `len(x)` would be the more typical way of retrieving the length of a string. – Oliver.R Apr 15 '20 at 23:29