Finding multiple occurrences of a string within a string in Python

Viewed 229859

How do I find multiple occurrences of a string within a string in Python? Consider this:

>>> text = "Allowed Hello Hollow"
>>> text.find("ll")
1
>>> 

So the first occurrence of ll is at 1 as expected. How do I find the next occurrence of it?

Same question is valid for a list. Consider:

>>> x = ['ll', 'ok', 'll']

How do I find all the ll with their indexes?

19 Answers

This code might not be the shortest/most efficient but it is simple and understandable

def findall(f, s):
    l = []
    i = -1
    while True:
        i = s.find(f, i+1)
        if i == -1:
            return l
        l.append(s.find(f, i))

findall('test', 'test test test test')
# [0, 5, 10, 15]

For the first version, checking a string:

def findall(text, sub):
    """Return all indices at which substring occurs in text"""
    return [
        index
        for index in range(len(text) - len(sub) + 1)
        if text[index:].startswith(sub)
    ]

print(findall('Allowed Hello Hollow', 'll'))
# [1, 10, 16]

No need to import re. This should run in linear time, as it only loops through the string once (and stops before the end, once there aren't enough characters left to fit the substring). I also find it quite readable, personally.

Note that this will find overlapping occurrences:

print(findall('aaa', 'aa'))
# [0, 1]

The following function finds all the occurrences of a string inside another while informing the position where each occurrence is found.

You can call the function using the test cases in the table below. You can try with words, spaces and numbers all mixed up.

The function works well with overlapping characters.

theString aString
"661444444423666455678966" "55"
"661444444423666455678966" "44"
"6123666455678966" "666"
"66123666455678966" "66"

Calling examples:

1. print("Number of occurrences: ", find_all("123666455556785555966", "5555"))
   
   output:
           Found in position:  7
           Found in position:  14
           Number of occurrences:  2
   
2. print("Number of occurrences: ", find_all("Allowed Hello Hollow", "ll "))

   output:
          Found in position:  1
          Found in position:  10
          Found in position:  16
          Number of occurrences:  3

3. print("Number of occurrences: ", find_all("Aaa bbbcd$#@@abWebbrbbbbrr 123", "bbb"))

   output:
         Found in position:  4
         Found in position:  21
         Number of occurrences:  2
         

def find_all(theString, aString):
    count = 0
    i = len(aString)
    x = 0

    while x < len(theString) - (i-1): 
        if theString[x:x+i] == aString:        
            print("Found in position: ", x)
            x=x+i
            count=count+1
        else:
            x=x+1
    return count

You can also do it with conditional list comprehension like this:

string1= "Allowed Hello Hollow"
string2= "ll"
print [num for num in xrange(len(string1)-len(string2)+1) if string1[num:num+len(string2)]==string2]
# [1, 10, 16]

I had randomly gotten this idea just a while ago. Using a While loop with string splicing and string search can work, even for overlapping strings.

findin = "algorithm alma mater alison alternation alpines"
search = "al"
inx = 0
num_str = 0

while True:
    inx = findin.find(search)
    if inx == -1: #breaks before adding 1 to number of string
        break
    inx = inx + 1
    findin = findin[inx:] #to splice the 'unsearched' part of the string
    num_str = num_str + 1 #counts no. of string

if num_str != 0:
    print("There are ",num_str," ",search," in your string.")
else:
    print("There are no ",search," in your string.")

I'm an amateur in Python Programming (Programming of any language, actually), and am not sure what other issues it could have, but I guess it's working fine?

I guess lower() could be used somewhere in it too if needed.

Related