51

I have a string and an arbitrary index into the string. I want find the first occurrence of a substring before the index.

An example: I want to find the index of the 2nd I by using the index and str.rfind()

s = "Hello, I am 12! I like plankton but I don't like Baseball."
index = 34 #points to the 't' in 'but'
index_of_2nd_I = s.rfind('I', index)
#returns = 36 and not 16 

Now I would expect rfind() to return the index of the 2nd I (16) but it returns 36. after looking it up in the docs I found out rfind does not stand for reverse find.

I'm totally new to Python so is there a built in solution to reverse find? Like reversing the string with some python [::-1] magic and using find, etc? Or will I have to reverse iterate char by char through the string?

Ooker
  • 1,969
  • 4
  • 28
  • 58
  • 3
    If jsz really is 12 then he/she is one bright kid ;-) – sidewinderguy May 25 '11 at 02:14
  • Yep, the start of reverse find is not the rightmost item. I find (on pun intended) the '`r`' in '`rfind`' misleading. It's less ambiguous to see `s.rfind(s,start,end)` as returning the *last* occurrence in `s[start:end]`. – YvesgereY Feb 28 '16 at 21:03

3 Answers3

65

Your call tell rfind to start looking at index 34. You want to use the rfind overload that takes a string, a start and an end. Tell it to start at the beginning of the string (0) and stop looking at index:

>>> s = "Hello, I am 12! I like plankton but I don't like Baseball."
>>> index = 34 #points to the 't' in 'but'
>>> index_of_2nd_I = s.rfind('I', 0, index)
>>>
>>> index_of_2nd_I
16
Roberto Caboni
  • 7,252
  • 10
  • 25
  • 39
Blair Conrad
  • 233,004
  • 25
  • 132
  • 111
  • I think this answer is wrong. It gives the index of the *first* 'I', not what the OP wanted. To find the 2nd 'I', `s.find('I', s.find('I')+1)` returns 16. To find the last 'I', `s.rfind('I')` would work. To find the indeces of all 'I' occurrences: `locs = [idx for idx,ltr in enumerate(s) if ltr == 'I']` – John Jul 31 '23 at 13:21
2

I became curious how to implement looking n times for string from end by rpartition and did this nth rpartition loop:

orig = s = "Hello, I am 12! I like plankton but I don't like Baseball."
found = tail = ''
nthlast = 2
lookfor = 'I'
for i in range(nthlast):
    tail = found+tail
    s,found,end = s.rpartition(lookfor)
    if not found:
        print "Only %i (less than %i) %r in \n%r" % (i, nthlast, lookfor, orig)
        break
    tail = end + tail
else:
    print(s,found,tail)
Tony Veijalainen
  • 5,447
  • 23
  • 31
0

To find the 2nd 'I':
s.find('I', s.find('I')+1) # returns 16

Find the last 'I':
s.rfind('I') # returns 36

Find the indeces of all 'I' occurrences:
locs = [idx for idx,ltr in enumerate(s) if ltr == 'I'] # [7, 16, 36]

John
  • 640
  • 2
  • 8
  • 18