正如 Joran Beasley 的回答所示,使用纯字符串函数比使用正则表达式进行静态字符串查找要快得多。
但是如果 N 非常大并且匹配不常见,那么测试 startswith N 次本身可能会大大降低速度。另外,由于您使用的是finditer 而不是findall,我怀疑您可能会担心这种情况。
使用str.find 可以两全其美。当然,最终这与在每个点使用 startswith 所做的工作相同——但它是在 C 中完成的,在没有匹配的情况下进行长距离压缩,速度提高了 20 倍。
另一方面,没有办法将这个重复的find 包装在一个简单的循环表达式中。 (除非您在闭包周围使用iter 构建一个复杂的包装器,但我怀疑这实际上会有所帮助。)因此,代码看起来会比 Joran 的 listcomp 更复杂。当匹配非常普遍时,它可能会更慢(因为在这种情况下,你大部分时间都花在循环中,并且显式循环语句比理解慢)。
从好的方面来说,额外的冗长意味着如何自定义它更明显。例如,如果您决定要跳过重叠匹配,只需使用 i += len(pattern) 而不是 i += 1。
def finditer(text, pattern):
i = 0
while True:
i = text.find(pattern, i)
if i == -1: return
yield i
i += 1
来自快速测试(在 64 位 Apple CPython 2.7.5 下):
In [931]: pattern = 'ha'
In [932]: text = 'hahahaha'
In [933]: %timeit [i for i in range(len(text)-len(pattern)+1) if text[i:].startswith(pattern)]
100000 loops, best of 3: 2.69 µs per loop
In [934]: %timeit list(finditer(text, pattern))
100000 loops, best of 3: 3.56 µs per loop
In [935]: text = ('hahahaha' + string.ascii_lowercase + 'ha')*100
pattern = 'ha'
In [936]: %timeit [i for i in range(len(text)-len(pattern)+1) if text[i:].startswith(pattern)]
100000 loops, best of 3: 1.74 ms per loop
In [937]: %timeit list(finditer(text, pattern))
100000 loops, best of 3: 180 µs per loop
因此,即使对于一个非常短的字符串(匹配率为 50%),它也几乎与 Joran 的代码一样快;对于具有 11% 匹配的更长字符串,它已经快了 9.6 倍。如果匹配更不常见,或者如果我们实际上不需要列表,显然它会赢得更大。