293

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

To get indices of the substrings, see How to find all occurrences of a substring?.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
santosh
  • 3,947
  • 3
  • 21
  • 32
  • 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

36 Answers36

449

string.count(substring), like in:

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

This is for non overlapping occurrences.
If you need to count overlapping occurrences, you'd better check the answers here, or just check my other answer below.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
jsbueno
  • 99,910
  • 10
  • 151
  • 209
  • 22
    What about this: `"GCAAAAAG".count("AAA")` which gives 1, while the correct answer is 3? – cartoonist May 09 '15 at 15:52
  • 23
    `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
  • Would you mind editing the other answer into this one, so that the key information is together at the top? – Karl Knechtel Jan 26 '23 at 18:31
  • sorry. I have the feeling that the shortness of this question is bit of a key for it to be spotted and help more people along time. I'd prefer to keep then separated, as this covers most normal uses. – jsbueno Jan 26 '23 at 19:36
  • Moreover - the 400+ votes are on the simple question. The code in the other answer is h flavored and not so simple - I think it would be cheating to include that code in this high voted answer. – jsbueno Jan 26 '23 at 19:39
37
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,519
  • 15
  • 25
21

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,821
  • 6
  • 26
  • 36
Don Question
  • 11,227
  • 5
  • 36
  • 54
  • 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-strings in a given string is to use a regular expression. With lookahead, it will find all the overlapping matches using the regular expression library's findall(). Here, left is the substring and right is the string to match.

>>> len(re.findall(r'(?=aa)', 'caaaab'))
3
wjandrea
  • 28,235
  • 9
  • 60
  • 81
Deepak Yadav
  • 632
  • 7
  • 14
  • 4
    maybe you could add len(re.findall(f'(?={sub_string})','caaaab')) to insert the sub string dynamically :) – Amresh Giri Apr 18 '20 at 19:56
  • @AmreshGiri You'd need to add [`re.escape(sub_string)`](https://docs.python.org/3/library/re.html#re.escape) to prevent regex metacharacters being interpreted. – wjandrea Jan 26 '23 at 18:40
11

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
  • 131
  • 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,405
  • 3
  • 22
  • 46
Anuj Gupta
  • 576
  • 5
  • 9
9

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
  • 533
  • 3
  • 11
Amith V V
  • 99
  • 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,172
  • 15
  • 22
5

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
  • 142,882
  • 41
  • 325
  • 378
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,960
  • 3
  • 45
  • 74
4

I will keep my accepted answer as the "simple and obvious way to do it", however, it 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.

Or it can be done by trick use of regular expressions, as can be seen at How to use regex to find all overlapping matches - and it can also make for fine code golfing.

This is my "hand made" count for overlapping occurrences 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))
wjandrea
  • 28,235
  • 9
  • 60
  • 81
jsbueno
  • 99,910
  • 10
  • 151
  • 209
4

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
  • 979
  • 10
  • 18
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,988
  • 2
  • 11
  • 26
3

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

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
  • 7,830
  • 13
  • 34
  • 43
fyngyrz
  • 2,458
  • 2
  • 36
  • 43
2

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,821
  • 6
  • 26
  • 36
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
  • 548
  • 1
  • 4
  • 19
  • _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

2+ others have already provided this solution, and 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
wjandrea
  • 28,235
  • 9
  • 60
  • 81
Babar-Baig
  • 689
  • 1
  • 12
  • 25
  • 1
    FWIW, `slen` and `range_s` are only used once, and I don't see any reason to make them variables, so you might as well do `range(len(string)-sslen+1)`. – wjandrea Jan 26 '23 at 19:07
  • Point taken. Only used them for clarity. I think more popular answers have used your approach. Hence my coment with the solution ... – Babar-Baig Mar 22 '23 at 22:02
1

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
  • 75
  • 1
  • 1
  • 10
1
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))
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
  • 639
  • 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(pattern, string)] 
print(d)

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

wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • This answer is not correct, I'm newish to python and what it actually did in my code was give me the position in an array. I assume it would just give me a list of positions if I had multiple matches. – Caribou May 25 '23 at 12:23
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,821
  • 6
  • 26
  • 36
skay
  • 11
  • 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
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

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.
  • 629
  • 1
  • 10
  • 25
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)
0

Using the assignment operator introduced in Python 3.8, we can write a short function that uses str.find() in a loop to find overlapping instances of a target substring within a string. There are a few other solutions already posted that use the same approach, but this one is shorter and faster.

The assignment expression not only serves to start the next find operation at the character after the last-found instance, it also provides the terminal expression for the while loop. str.find() returns -1 if the substring isn't found, and adding 1 to this yields 0, which is false, thereby exiting the loop when no more matches are found.

# count overlapping occurrences of a substring in a string
def count_overlapping(haystack, needle, start=0, count=0):
    while start := haystack.find(needle, start) + 1:
        count += 1
    return count

print(count_overlapping("moomoooo", "oo"))    # 4

To optimize performance further, we can look up haystack.find once outside the loop and store that in a local variable. This will be faster when there are more than a couple of matches.

# count overlapping occurrences of a substring in a string
def count_overlapping(haystack, needle, start=0, count=0):
    haystack_find = haystack.find
    while start := haystack_find(needle, start) + 1:
        count += 1
    return count
kindall
  • 178,883
  • 35
  • 278
  • 309
-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