Ответ 1
"Итак, обновленный вопрос теперь, почему поиск не работает?"
В этом конкретном случае, где используется буквальная строка, а не шаблон регулярного выражения, действительно 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