Chiko
Chiko

Reputation: 606

Getting the first appearance of a any char from a set in a string - python

is there a better way to find the first appearance of one of the chars: 'x','y','z' in someStr?

def findFirstAppearance(someStr):
    x = someStr.find('x');
    y = someStr.find('y');
    z = someStr.find('z');

    if x == -1: x= len(someStr);
    if y == -1: y= len(someStr);
    if z == -1: z= len(someStr); 

    return min(x,y,z);

for example: for someStr = "axby" it should return 1. for someStr = "aybx" it should also return 1.

thanks!

Upvotes: 1

Views: 1901

Answers (6)

Steven Rumbalski
Steven Rumbalski

Reputation: 45542

Here's an alternative using regular expressions.

import re
def find_first_dx(needles, haystack):
    match = re.search('|'.join(map(re.escape, needles)), haystack)
    return match.start() if match else -1

Examples:

>>> find_first_dx('xyz', 'abcyax')
3
>>> find_first_dx('xyz.', 'a.bcyax')
1
>>> find_first_dx('xyz', 'fee fi foe fum')
-1
>>> find_first_dx(['foe', 'fum'], 'fee fi foe fum')
7

Upvotes: 1

jsbueno
jsbueno

Reputation: 110271

For a lot of chars, you should seriously think about using a regular expression, especially if you are doing this in a loop in your application:

import re
def findall(string, chars)
    m = re.search("[%s]" % chars, string, re.DOTALL)
    if m:
        return m.start()
    return -1

this should be at least 100x faster than a pure-python loop with a call to "find" for each char.

Just be aware that if you need to find a char that is used for other purposes inside regexps "[ ]" , you should escape them (like "-", "^")

Upvotes: 0

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 250941

Use enumerate(), it yields a tuple for each character of the string.

Tuple's first element is the index and second element is the character itself.

In [103]: def find_first(strs):
   .....:     for i,x in enumerate(strs):
   .....:         if x in 'xyz': #if current character is either
                                 #'x' or 'y' or 'z' then return index
   .....:             return i
   .....:     return -1              #if the loop completed successfully then return -1
   .....: 

In [104]: find_first("fooxbaryzx")
Out[104]: 3

In [105]: find_first("qwerty")
Out[105]: 5

In [106]: find_first("qwert")
Out[106]: -1

In [107]: find_first("axby")
Out[107]: 1

In [108]: find_first("aybx")
Out[108]: 1

Upvotes: 0

zenpoy
zenpoy

Reputation: 20126

This should work:

def findany(s1, s2):
    for i, x in enumerate(s1):
        if x in s2:
            return i
    return -1

Upvotes: 0

DSM
DSM

Reputation: 353059

Maybe:

>>> s = 'this string x contains y several letters z'
>>> next(i for i,c in enumerate(s) if c in 'xyz')
12
>>> s[12]
'x'

This will raise an exception if it's not found, which could be fixed by using a default value:

>>> next(i for i,c in enumerate(s) if c in 'Q')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> next((i for i,c in enumerate(s) if c in 'Q'), -1)
-1

You could also pre-construct a set to test membership in:

>>> special = set("vmp")
>>> next((i for i,c in enumerate(s) if c in special), -1)
27

which might be faster if there were a lot of letters to test against; it'll depend a lot on the sizes involved. Easy to experiment if it matters, but (spoiler alert) it probably doesn't.

Upvotes: 2

jdm
jdm

Reputation: 10050

I think this is what you're looking for. This finds the first occurance of one of may chars (items) in a string. It works just like str.find.

def findany(string, items, start, end=-1):
    if end == -1:
        end = len(string)

    for i in range(start, end):
        c = string[i]
        if c in items:
            return i

    return -1

#      01234567
inp = "hellozxy"

print findany(inp, "xyz")    # 5 = z
print findany(inp, "?")      # -1 = not found
print findany(inp, ["o", "l"], 3)    # 3, skips the first 'l'

Note: You pass a list of chars (1-character strings) as items. In python, a string is just that. If you pass something like ["x", "y", "blah"], it won't work (it'll ignore "blah").

Upvotes: 0

Related Questions