В чем разница между re.search и re.match?

В чем разница между функциями search() и match() в Python re модуле?

Я прочитал документацию (текущая документация), но я никогда не Запомни. Мне все время приходится искать и заново учить. Я надеюсь, что кто-то четко ответит на него с примерами, чтобы (возможно) он запал мне в голову. Или, по крайней мере, у меня будет лучшее место, чтобы вернуться с моим вопросом, и мне потребуется меньше времени, чтобы заново выучить его.


person Daryl Spitzer    schedule 08.10.2008    source источник


Ответы (8)


re.match закреплен в начале строки. Это не имеет ничего общего с символами новой строки, поэтому это не то же самое, что использовать ^ в шаблоне.

Как говорится в документации re.match:

Если ноль или более символов в начале строки соответствуют шаблону регулярного выражения, верните соответствующий экземпляр MatchObject. Вернуть None, если строка не соответствует шаблону; обратите внимание, что это отличается от совпадения нулевой длины.

Примечание. Если вы хотите найти совпадение в любом месте строки, используйте вместо этого search().

re.search выполняет поиск по всей строке, как указано в документации:

Просканируйте строку в поисках места, в котором шаблон регулярного выражения дает совпадение, и верните соответствующий экземпляр MatchObject. Вернуть None, если ни одна позиция в строке не соответствует шаблону; обратите внимание, что это отличается от поиска совпадения нулевой длины в некоторой точке строки.

Поэтому, если вам нужно сопоставить начало строки или сопоставить всю строку, используйте match. Это быстрее. В противном случае используйте search.

В документации есть специальный раздел для match и search. который также охватывает многострочные строки:

Python предлагает две разные примитивные операции, основанные на регулярных выражениях: match проверяет совпадение только в начале строки, а search проверяет совпадение где угодно в строке (это это то, что Perl делает по умолчанию).

Обратите внимание, что match может отличаться от search даже при использовании регулярного выражения, начинающегося с '^': '^' соответствует только началу строки или в режиме MULTILINE также сразу после новой строки. Операция «match» завершается успешно только в том случае, если шаблон совпадает в начале строки независимо от режима или в начальной позиции, заданной необязательным аргументом pos, независимо от того, является ли ему предшествует новая строка.

А теперь хватит разговоров. Пришло время увидеть пример кода:

# example code:
string_with_newlines = """something
someotherthing"""

import re

print re.match('some', string_with_newlines) # matches
print re.match('someother', 
               string_with_newlines) # won't match
print re.match('^someother', string_with_newlines, 
               re.MULTILINE) # also won't match
print re.search('someother', 
                string_with_newlines) # finds something
print re.search('^someother', string_with_newlines, 
                re.MULTILINE) # also finds something

m = re.compile('thing$', re.MULTILINE)

print m.match(string_with_newlines) # no match
print m.match(string_with_newlines, pos=4) # matches
print m.search(string_with_newlines, 
               re.MULTILINE) # also matches
person nosklo    schedule 08.10.2008
comment
А как насчет строк, содержащих новые строки? - person Daryl Spitzer; 08.10.2008
comment
даже со строками, содержащими символы новой строки, match () соответствует только НАЧАЛУ строки. - person nosklo; 08.10.2008
comment
Это тот ответ, на который я надеялся! (Особенно сейчас, когда вы привели пример.) - person Daryl Spitzer; 08.10.2008
comment
Тогда зачем кому-то использовать ограниченный match, а не более общий search? это для скорости? - person Alby; 23.07.2014
comment
Соответствие @Alby выполняется намного быстрее, чем поиск, поэтому вместо выполнения regex.search (word) вы можете выполнить regex.match ((. *?) Word (. *?)) И получить большую производительность, если вы работаете с миллионами образцы. - person ivan_bilan; 24.05.2016
comment
Что ж, это глупо. Зачем называть это match? Является ли это умным маневром, чтобы засеять API неинтуитивными именами, чтобы заставить меня читать документацию? Я все равно этого не сделаю! Бунтарь! - person Sammaron; 16.09.2016
comment
@ivan_bilan match выглядит немного faster, чем поиск при использовании того же регулярного выражения, но ваш пример кажется неверным согласно тесту производительности: stackoverflow.com/questions/180986/ - person baptx; 21.01.2019
comment
При использовании регулярного выражения, начинающегося с '^' и с неопределенным MULTILINE, является ли match тем же, что и search (дает тот же результат)? - person Zitao Wang; 19.08.2019

search найти что-нибудь в строке и вернуть соответствующий объект.

match найдите что-нибудь в начале строки и верните соответствующий объект.

person Dhanasekaran Anbalagan    schedule 31.12.2011

сопоставление выполняется намного быстрее, чем поиск, поэтому вместо выполнения regex.search ("word") вы можете выполнить regex.match ((. *?) word (. *?)) и получить большую производительность, если вы работаете с миллионами образцы.

Этот комментарий от @ivan_bilan под принятым ответом выше заставил меня задуматься, действительно ли такой хак ускоряет что-либо, так что давайте посмотрим, сколько тонн производительности вы действительно получите.

Я подготовил следующий набор тестов:

import random
import re
import string
import time

LENGTH = 10
LIST_SIZE = 1000000

def generate_word():
    word = [random.choice(string.ascii_lowercase) for _ in range(LENGTH)]
    word = ''.join(word)
    return word

wordlist = [generate_word() for _ in range(LIST_SIZE)]

start = time.time()
[re.search('python', word) for word in wordlist]
print('search:', time.time() - start)

start = time.time()
[re.match('(.*?)python(.*?)', word) for word in wordlist]
print('match:', time.time() - start)

Я сделал 10 измерений (1M, 2M, ..., 10M слов), которые дали мне следующий график:

график соответствия регулярному выражению или поисковой строке тестовой линии

В результате линии получаются на удивление (на самом деле не так уж и удивительно) прямыми. И функция search работает (немного) быстрее с этой конкретной комбинацией шаблонов. Мораль этого теста: Избегайте чрезмерной оптимизации кода.

person Jeyekomon    schedule 07.04.2018
comment
+1 за фактическое расследование предположений, стоящих за заявлением, которое следует принимать за чистую монету - спасибо. - person Robert Dodier; 30.10.2018
comment
Действительно, комментарий @ivan_bilan выглядит неправильно, но функция match по-прежнему работает быстрее, чем функция search, если вы сравниваете то же самое регулярное выражение. Вы можете проверить свой скрипт, сравнив re.search('^python', word) с re.match('python', word) (или re.match('^python', word), что то же самое, но его легче понять, если вы не читаете документацию и, похоже, не влияет на производительность) - person baptx; 21.01.2019
comment
@baptx Я не согласен с утверждением, что функция match обычно работает быстрее. match быстрее, если вы хотите искать в начале строки, search быстрее, когда вы хотите искать по всей строке. Что соответствует здравому смыслу. Вот почему @ivan_bilan ошибался - он использовал match для поиска по всей строке. Вот почему вы правы - вы использовали match для поиска в начале строки. Если вы не согласны со мной, попробуйте найти регулярное выражение для match, которое быстрее, чем re.search('python', word) и выполняет ту же работу. - person Jeyekomon; 22.01.2019
comment
@baptx Также, в качестве сноски, re.match('python') немного быстрее, чем re.match('^python'). Должно быть. - person Jeyekomon; 22.01.2019
comment
@Jeyekomon, да, именно это я имел в виду, функция match работает немного быстрее, если вы хотите искать в начале строки (по сравнению, например, с использованием функции search для поиска слова в начале строки с re.search('^python', word)). Но я нахожу это странным, если вы укажете функции search искать в начале строки, она должна быть такой же быстрой, как функция match. - person baptx; 23.01.2019
comment
@baptx Я предполагаю, что функция search должна анализировать и обрабатывать информацию ^, в то время как match уже жестко запрограммировала ее в двоичном файле c. В любом случае разница в скорости на моем ПК составляет всего около 10%. - person Jeyekomon; 24.01.2019
comment
@Jeyekomon, это могло произойти отсюда, но я не думаю, что это так, поскольку, если мы дадим ненужный символ ^ функции match, это не займет больше времени, чтобы его прочитать (иногда это было даже немного быстрее). - person baptx; 26.01.2019
comment
То, что re.search() быстрее для этого конкретного регулярного выражения, совсем не удивительно. Шаблон re.match() дольше обрабатывается хотя бы потому, что он захватывает начало строки. - person Denis de Bernardy; 21.07.2019

re.search поиск шаблона по всей строке, тогда как re.match не ищет шаблон; в противном случае у него нет другого выбора, кроме как сопоставить его в начале строки.

person xilun    schedule 08.10.2008
comment
Почему совпадают в начале, но не до конца строки (fullmatch в phyton 3.4)? - person Smit Johnth; 14.07.2015

Вы можете обратиться к приведенному ниже примеру, чтобы понять работу re.match и re.search.

a = "123abc"
t = re.match("[a-z]+",a)
t = re.search("[a-z]+",a)

re.match вернет none, но re.search вернет abc.

person ldR    schedule 30.07.2015
comment
Просто хочу добавить, что поиск вернет объект _sre.SRE_Match (или None, если не найден). Чтобы получить abc, вам нужно вызвать t.group () - person SanD; 01.03.2017

Разница в том, что re.match() вводит в заблуждение любого, кто привык к сопоставлению регулярных выражений Perl, grep или sed, а re.search() - нет. :-)

Более трезво, как отмечает Джон Д. Кук, re.match() "ведет себя так, как если бы каждый шаблон был добавлен ^ . " Другими словами, re.match('pattern') равно re.search('^pattern'). Таким образом, он закрепляет левую сторону шаблона. Но он также не привязывает правую сторону шаблона:, для которого по-прежнему требуется завершающий $.

Откровенно говоря, учитывая вышесказанное, я думаю, что re.match() следует устареть. Мне было бы интересно узнать, почему его следует сохранить.

person CODE-REaD    schedule 21.05.2016
comment
ведет себя так, как будто перед каждым шаблоном стоит знак ^. верно только в том случае, если вы не используете многострочную опцию. Правильное утверждение: ... имеет начало \ A - person JoelFan; 28.06.2017

re.match пытается сопоставить шаблон в начале строки. re.search пытается сопоставить шаблон по всей строке, пока не найдет совпадение.

person cschol    schedule 08.10.2008

Намного короче:

  • search просматривает всю строку.

  • match просматривает только начало строки.

Следом за Ex говорит это:

>>> a = "123abc"
>>> re.match("[a-z]+",a)
None
>>> re.search("[a-z]+",a)
abc
person U11-Forward    schedule 31.10.2018