我尝试使用re.match
模块比较re.search
和timeit
,我发现当我想要找到的字符串位于字符串的开头时,匹配优于搜索。< / p>
>>> s1 = '''
... import re
... re.search(r'hello','helloab'*100000)
... '''
>>> timeit.timeit(stmt=s1,number=10000)
32.12064480781555
>>> s = '''
... import re
... re.match(r'hello','helloab'*100000)
... '''
>>> timeit.timeit(stmt=s,number=10000)
30.9136700630188
现在,我知道匹配在字符串的开头查找模式并返回一个对象(如果找到),但我想知道搜索是如何操作的。
在开头找到字符串后,搜索是否会执行任何额外的匹配,这会使其减速?
更新
在使用@David Robinsons代码之后,我得到了他的结果。
>>> print timeit.timeit(stmt="r.match('hello')",
... setup="import re; s = 'helloab'*100000; r = re.compile('hello')",
... number = 10000000)
49.9567620754
>>> print timeit.timeit(stmt="r.search('hello')",
... setup="import re; s = 'helloab'*100000; r = re.compile('hello')",
... number = 10000000)
35.6694438457
那么,更新后的问题现在为什么search
表现不佳match
?
答案 0 :(得分:12)
“那么,更新后的问题是为什么搜索效果不佳?”
在这个使用文字字符串而不是正则表达式模式的特定实例中,对于默认的CPython实现,re.search
确实比re.match
略快(我没有在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 code behind those modules,搜索代码似乎有内置优化to quickly match patterns prefixed with a string lateral。在上面的示例中,整个模式是一个没有正则表达式模式的文字字符串,因此这个优化的例程用于匹配整个模式。
注意一旦我们引入正则表达式符号,性能会如何降低,并且随着文字字符串前缀变短:
>>> 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
答案 1 :(得分:6)
在我的机器上(Mac OS 10.7.3上的Python 2.7.3,1.7 GHz Intel Core i5),完成字符串构造,导入re和设置中的正则表达式编译,并执行10000000次迭代而不是10次时,我发现相反:
import timeit
print timeit.timeit(stmt="r.match(s)",
setup="import re; s = 'helloab'*100000; r = re.compile('hello')",
number = 10000000)
# 6.43165612221
print timeit.timeit(stmt="r.search(s)",
setup="import re; s = 'helloab'*100000; r = re.compile('hello')",
number = 10000000)
# 3.85176897049