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


528

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

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

Ответы:


508

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

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

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

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

re.searchищет всю строку, как сказано в документации :

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

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

В документации есть специальный раздел для matchvs.,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

Как насчет строк, содержащих переводы строки?
Дэрил Спитцер

26
Зачем кому-то использовать ограниченное, matchа не более общее search? это для скорости?
Алби

13
Сравнение @Alby намного быстрее, чем поиск, поэтому вместо regex.search ("word") вы можете выполнить regex.match ((. *?) Word (. *?)) И получить массу производительности, если вы работаете с миллионы образцов.
ivan_bilan

20
Ну, это глупо. Зачем называть это match? Это умный маневр, чтобы заполнить API с неинтуитивными именами, чтобы заставить меня читать документацию? Я все еще не буду этого делать! Бунтарь!
Саммарон

1
@ivan_bilan matchвыглядит немного хуже, fasterчем поиск при использовании того же регулярного выражения, но ваш пример кажется неверным в соответствии с тестом производительности: stackoverflow.com/questions/180986/…
baptx


49

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


5
Почему сопоставлять в начале, но не до конца строки ( fullmatchв фитоне 3.4)?
Смит Johnth

49

сопоставление выполняется намного быстрее, чем поиск, поэтому вместо выполнения 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функция (немного) быстрее, учитывая эту конкретную комбинацию шаблонов. Мораль этого теста: избегайте чрезмерной оптимизации вашего кода.


12
+1 за фактическое исследование предположений, лежащих в основе заявления, которое должно быть принято за чистую монету - спасибо.
Роберт Додье

Действительно, комментарий @ivan_bilan выглядит неправильно, но matchфункция все равно быстрее, чем searchфункция, если вы сравните одно и то же регулярное выражение. Вы можете проверить свой сценарий, сравнив re.search('^python', word)его re.match('python', word)(или re.match('^python', word)который такой же, но легче понять, если вы не читаете документацию и, похоже, не
влияете

@baptx Я не согласен с утверждением, что matchфункция, как правило, быстрее. Чем matchбыстрее, когда вы хотите искать в начале строки, тем searchбыстрее, когда вы хотите искать по всей строке. Что соответствует здравому смыслу. Вот почему @ivan_bilan был не прав - он использовал matchпоиск по всей строке. Вот почему вы правы - вы использовали matchпоиск в начале строки. Если вы не согласны со мной, попробуйте найти регулярное выражение для matchэтого быстрее, чем re.search('python', word)и делает ту же работу.
Jeyekomon

@baptx Кроме того , в качестве сноски, то re.match('python') это немного быстрее , чем re.match('^python'). Должно быть.
Jeyekomon

@Jeyekomon да, это то, что я имел в виду, matchфункция работает немного быстрее, если вы хотите искать в начале строки (по сравнению с использованием searchфункции для поиска слова в начале строки, re.search('^python', word)например). Но я нахожу это странным, если вы скажете searchфункции выполнять поиск в начале строки, она должна быть такой же быстрой, как и matchфункция.
baptx

31

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

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

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


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

30

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

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

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


4
"ведет себя так, как будто каждый шаблон имеет ^ предваряющий." Истинно, только если вы не используете многострочный параметр. Правильное утверждение «... имеет \ A prepended»
JoelFan

14

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


3

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

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

  • match сканирует только начало строки.

После Ex говорит это:

>>> a = "123abc"
>>> re.match("[a-z]+",a)
None
>>> re.search("[a-z]+",a)
abc
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.