“所以,现在更新的问题是为什么搜索性能优于匹配?”
在这个使用文字字符串而不是正则表达式模式的特定实例中,确实re.search
比re.match
默认的 CPython 实现稍快(我没有在 Python 的其他版本中对此进行测试)。
>>> print timeit.timeit(stmt="r.match(s)",
... setup="import re; s = 'helloab'*100000; r = re.compile('hello')",
... number = 10000000)
3.29107403755
>>> print timeit.timeit(stmt="r.search(s)",
... setup="import re; s = 'helloab'*100000; r = re.compile('hello')",
... number = 10000000)
2.39184308052
查看这些模块背后的 C 代码,搜索代码似乎具有内置优化功能,可以快速匹配以字符串横向为前缀的模式。在上面的示例中,整个模式是一个没有正则表达式模式的文字字符串,因此这个优化的例程用于匹配整个模式。
请注意,一旦我们引入正则表达式符号,性能会如何下降,并且随着文字字符串前缀变短:
>>> print timeit.timeit(stmt="r.search(s)",
... setup="import re; s = 'helloab'*100000; r = re.compile('hell.')",
... number = 10000000)
3.20765399933
>>>
>>> print timeit.timeit(stmt="r.search(s)",
... setup="import re; s = 'helloab'*100000; r = re.compile('hel.o')",
... number = 10000000)
3.31512498856
>>> print timeit.timeit(stmt="r.search(s)",
... setup="import re; s = 'helloab'*100000; r = re.compile('he.lo')",
... number = 10000000)
3.31983995438
>>> print timeit.timeit(stmt="r.search(s)",
... setup="import re; s = 'helloab'*100000; r = re.compile('h.llo')",
... number = 10000000)
3.39261603355
对于包含正则表达式模式的部分模式,SRE_MATCH用于确定匹配。这与后面的代码基本相同re.match
。
re.match
请注意,如果模式以正则表达式模式而不是文字字符串开头,结果是如何接近的(稍微快一点)。
>>> print timeit.timeit(stmt="r.match(s)",
... setup="import re; s = 'helloab'*100000; r = re.compile('.ello')",
... number = 10000000)
3.22782492638
>>> print timeit.timeit(stmt="r.search(s)",
... setup="import re; s = 'helloab'*100000; r = re.compile('.ello')",
... number = 10000000)
3.31773591042
换句话说,忽略search
和match
具有不同目的的事实re.search
比re.match
仅当模式是文字字符串时要快。
当然,如果您使用的是文字字符串,那么使用字符串操作可能会更好。
>>> # Detecting exact matches
>>> print timeit.timeit(stmt="s == r",
... setup="s = 'helloab'*100000; r = 'hello'",
... number = 10000000)
0.339027881622
>>> # Determine if string contains another string
>>> print timeit.timeit(stmt="s in r",
... setup="s = 'helloab'*100000; r = 'hello'",
... number = 10000000)
0.479326963425
>>> # detecting prefix
>>> print timeit.timeit(stmt="s.startswith(r)",
... setup="s = 'helloab'*100000; r = 'hello'",
... number = 10000000)
1.49393510818
>>> print timeit.timeit(stmt="s[:len(r)] == r",
... setup="s = 'helloab'*100000; r = 'hello'",
... number = 10000000)
1.21005606651