私はこれと同じ問題を抱えていて、ここで解決策のタイミングを調べました(他のオプションよりも大幅に遅い@wwiiのmap/list-compのものを除く)。元のバージョンの Cython バージョンも追加しました。
これらはすべて Python v2.7 で作成およびテストしました。(Unicode 文字列の代わりに) バイト文字列を使用していました。Python v3 でバイト文字列を操作するために、正規表現メソッドに別のものが必要かどうかはわかりません。「マーク」は、null バイトになるようにハードコードされています。これは簡単に変更できました。
バイト文字列全体がヌルバイトの場合、すべてのメソッドは -1 を返します。これらはすべて IPython でテストされています (% で始まる行は特別です)。
import re
def f1(s): # original version
for i, c in enumerate(s):
if c != b'\0': return i
return -1
def f2(s): # @ChristopherMahan's version
i = 0
for c in s:
if c != b'\0': return i
i += 1
return -1
def f3(s): # @AndrewClark's alternate version
# modified to use optional default argument instead of catching StopIteration
return next((i for i, c in enumerate(s) if c != b'\0'), -1)
def f4(s): # @AndrewClark's version
match = re.search(br'[^\0]', s)
return match.start() if match else -1
_re = re.compile(br'[^\0]')
def f5(s): # @AndrewClark's version w/ precompiled regular expression
match = _re.search(s)
return match.start() if match else -1
%load_ext cythonmagic
%%cython
# original version optimized in Cython
import cython
@cython.boundscheck(False)
@cython.wraparound(False)
def f6(bytes s):
cdef Py_ssize_t i
for i in xrange(len(s)):
if s[i] != b'\0': return i
return -1
タイミング結果:
s = (b'\x00' * 32) + (b'\x01' * 32) # test string
In [11]: %timeit f1(s) # original version
100000 loops, best of 3: 2.48 µs per loop
In [12]: %timeit f2(s) # @ChristopherMahan's version
100000 loops, best of 3: 2.35 µs per loop
In [13]: %timeit f3(s) # @AndrewClark's alternate version
100000 loops, best of 3: 3.07 µs per loop
In [14]: %timeit f4(s) # @AndrewClark's version
1000000 loops, best of 3: 1.91 µs per loop
In [15]: %timeit f5(s) # @AndrewClark's version w/ precompiled regular expression
1000000 loops, best of 3: 845 ns per loop
In [16]: %timeit f6(s) # original version optimized in Cython
1000000 loops, best of 3: 305 ns per loop
全体的に、@ChristopherMahan のバージョンは、元のバージョンよりもわずかに高速です (明らかにenumerate
、独自のカウンターを使用するよりも遅いです)。next
(@AndrewClarkの代替バージョン)メソッドを使用すると、1行の形式で本質的に同じものであるにもかかわらず、元のメソッドよりも遅くなります。
正規表現 (@AndrewClark のバージョン) を使用すると、特に正規表現をプリコンパイルする場合に、ループよりも大幅に高速になります!
次に、Cython を使用できる場合は、それが断然高速です。正規表現の使用が遅いというOPの懸念は検証されていますが、Pythonのループはさらに遅くなります。Cython のループは非常に高速です。