文字列内の文字セットの最初のインデックスを見つける方法 質問する

文字列内の文字セットの最初のインデックスを見つける方法 質問する

次のように、文字列内の「特殊」文字が最初に出現するインデックスを見つけたいと思います。

>>> "Hello world!".index([' ', '!'])
5

…ただし、これは有効な Python 構文ではありません。もちろん、この動作をエミュレートする関数を書くこともできます。

def first_index(s, characters):
    i = []
    for c in characters:
        try:
            i.append(s.index(c))
        except ValueError:
            pass
    if not i:
        raise ValueError
    return min(i)

正規表現を使用することもできますが、どちらの解決策も少しやり過ぎのようです。Python でこれを行う「まともな」方法はあるでしょうか?

ベストアンサー1

使用できます列挙するそしてとともにジェネレータ式最初に一致したものを取得するか、s に文字がない場合は None を返します。

s = "Hello world!"

st = {"!"," "}
ind = next((i for i, ch  in enumerate(s) if ch in st),None)
print(ind)

一致するものがない場合、デフォルトの戻り値として任意の値を次に渡すことができます。

関数を使用して ValueError を発生させる場合:

def first_index(s, characters):
    st = set(characters)
    ind = next((i for i, ch in enumerate(s) if ch in st), None)
    if ind is not None:
        return ind
    raise ValueError

入力が小さい場合、セットを使用しても大きな違いはありませんが、大きな文字列の場合はより効率的になります。

いくつかのタイミング:

文字列内の文字セットの最後の文字:

In [40]: s = "Hello world!" * 100    
In [41]: string = s    
In [42]: %%timeit
st = {"x","y","!"}
next((i for i, ch in enumerate(s) if ch in st), None)
   ....: 
1000000 loops, best of 3: 1.71 µs per loop    
In [43]: %%timeit
specials = ['x', 'y', '!']
min(map(lambda x: (string.index(x) if (x in string) else len(string)), specials))
   ....: 
100000 loops, best of 3: 2.64 µs per loop

文字列に含まれない、より大きな文字セット:

In [44]: %%timeit
st = {"u","v","w","x","y","z"}
next((i for i, ch in enumerate(s) if ch in st), None)
   ....: 
1000000 loops, best of 3: 1.49 µs per loop

In [45]: %%timeit
specials = ["u","v","w","x","y","z"]
min(map(lambda x: (string.index(x) if (x in string) else len(string)), specials))
   ....: 
100000 loops, best of 3: 5.48 µs per loop

文字列内の文字セットの最初の文字:

In [47]: %%timeit
specials = ['H', 'y', '!']
min(map(lambda x: (string.index(x) if (x in string) else len(string)), specials))
   ....: 
100000 loops, best of 3: 2.02 µs per loop

In [48]: %%timeit
st = {"H","y","!"}
next((i for i, ch in enumerate(s) if ch in st), None)
   ....: 
1000000 loops, best of 3: 903 ns per loop

おすすめ記事