This is because str.index(ch) will return the index where ch occurs the first time. Try:
def find(s, ch):
return [i for i, ltr in enumerate(s) if ltr == ch]
This will return a list of all indexes you need.
P.S. Hugh's answer shows a generator function (it makes a difference if the list of indexes can get large). This function can also be adjusted by changing [] to ().
This is because str.index(ch) will return the index where ch occurs the first time. Try:
def find(s, ch):
return [i for i, ltr in enumerate(s) if ltr == ch]
This will return a list of all indexes you need.
P.S. Hugh's answer shows a generator function (it makes a difference if the list of indexes can get large). This function can also be adjusted by changing [] to ().
I would go with Lev, but it's worth pointing out that if you end up with more complex searches that using re.finditer may be worth bearing in mind (but re's often cause more trouble than worth - but sometimes handy to know)
test = "ooottat"
[ (i.start(), i.end()) for i in re.finditer('o', test)]
# [(0, 1), (1, 2), (2, 3)]
[ (i.start(), i.end()) for i in re.finditer('o+', test)]
# [(0, 3)]
How to find all occurrences of a substring in a string while ignore some characters in Python?
python - Finding All Positions Of A Character In A String - Stack Overflow
python - Find all the occurrences of a character in a string - Stack Overflow
python - How to find all occurrences of a substring? - Stack Overflow
Videos
I'd like to find all occurrences of a substring while ignore some characters. How can I do it in Python?
Example:
long_string = 'this is a t`es"t. Does the test work?' small_string = "test" chars_to_ignore = ['"', '`'] print(find_occurrences(long_string, small_string))
should return [(10, 16), (27, 31)] because we want to ignore the presence of chars ` and ".
-
(10, 16)is the start and end index of t`es"t inlong_string, -
(27, 31)is the start and end index oftestinlong_string.
Using enumerate is the standard way to go. Although, you can take advantage of the speed of str.find for time-critical operations.
Code
def find_all(s, c):
idx = s.find(c)
while idx != -1:
yield idx
idx = s.find(c, idx + 1)
print(*find_all('Apples are totally awesome', 'o')) # 12 23
I made the above return a generator for elegance and to account for very large strings. Put it can of course be casted to a list if need be.
Benchmark
Here is a benchmark against a solution using enumerate and a list-comprehension. Both solutions have linear time-complexity, but str.find is significantly faster.
import timeit
def find_all_enumerate(s, c):
return [i for i, x in enumerate(s) if c == x]
print(
'find_all:',
timeit.timeit("list(find_all('Apples are totally awesome', 'o'))",
setup="from __main__ import find_all")
)
print(
'find_all_enumerate:',
timeit.timeit("find_all_enumerate('Apples are totally awesome', 'o')",
setup="from __main__ import find_all_enumerate")
)
Output
find_all: 1.1554179692960915
find_all_enumerate: 1.9171753468076869
Use you a list comprehension for great good:
[ind for ind, ch in enumerate(sentence) if ch.lower() == 'a']
will return a list of all the numbers you want. Print as desired.
And I assumed, based on your example, you don't care about case, hence the lower() function call. Using Python 3's asterisk splat operator (*) you could do all of this as a one liner; but that I will leave as an exercise for the reader.
The function:
def findOccurrences(s, ch):
return [i for i, letter in enumerate(s) if letter == ch]
findOccurrences(yourString, '|')
will return a list of the indices of yourString in which the | occur.
if you want index of all occurrences of | character in a string you can do this
import re
example_string = "aaaaaa|bbbbbb|ccccc|dddd"
indexes = [x.start() for x in re.finditer('\|', example_string)]
print(indexes) # <-- [6, 13, 19]
also you can do
indexes = [x for x, v in enumerate(str) if v == '|']
print(indexes) # <-- [6, 13, 19]
There is no simple built-in string function that does what you're looking for, but you could use the more powerful regular expressions:
import re
[m.start() for m in re.finditer('test', 'test test test test')]
#[0, 5, 10, 15]
If you want to find overlapping matches, lookahead will do that:
[m.start() for m in re.finditer('(?=tt)', 'ttt')]
#[0, 1]
If you want a reverse find-all without overlaps, you can combine positive and negative lookahead into an expression like this:
search = 'tt'
[m.start() for m in re.finditer('(?=%s)(?!.{1,%d}%s)' % (search, len(search)-1, search), 'ttt')]
#[1]
re.finditer returns a generator, so you could change the [] in the above to () to get a generator instead of a list which will be more efficient if you're only iterating through the results once.
>>> help(str.find)
Help on method_descriptor:
find(...)
S.find(sub [,start [,end]]) -> int
Thus, we can build it ourselves:
def find_all(a_str, sub):
start = 0
while True:
start = a_str.find(sub, start)
if start == -1: return
yield start
start += len(sub) # use start += 1 to find overlapping matches
list(find_all('spam spam spam spam', 'spam')) # [0, 5, 10, 15]
No temporary strings or regexes required.