Qual é a diferença entre re.search e re.match?

527

Qual é a diferença entre as funções search()e match()no módulo Pythonre ?

Eu li a documentação ( documentação atual ), mas nunca me lembro. Eu continuo tendo que procurar e reaprender. Espero que alguém responda claramente com exemplos, para que (talvez) fique na minha cabeça. Ou pelo menos terei um lugar melhor para retornar com a minha pergunta e levará menos tempo para reaprendê-la.

Daryl Spitzer
fonte

Respostas:

508

re.matchestá ancorado no início da string. Isso não tem nada a ver com novas linhas, portanto, não é o mesmo que usar ^no padrão.

Como a documentação re.match diz:

Se zero ou mais caracteres no início da sequência corresponderem ao padrão de expressão regular, retorne uma MatchObjectinstância correspondente . Retorne Nonese a sequência não corresponder ao padrão; observe que isso é diferente de uma correspondência de comprimento zero.

Nota: Se você deseja localizar uma correspondência em qualquer lugar da string, use search() .

re.searchpesquisa a cadeia inteira, como diz a documentação :

Examine a cadeia de caracteres procurando um local em que o padrão de expressão regular produz uma correspondência e retorne uma MatchObjectinstância correspondente . Retorne Nonese nenhuma posição na string corresponder ao padrão; observe que isso é diferente de encontrar uma correspondência de comprimento zero em algum momento da string.

Portanto, se você precisar corresponder no início da string ou usar toda a string, use match. É mais rápido. Caso contrário, use search.

A documentação possui uma seção específica para matchvs.search que também abrange seqüências de várias linhas:

O Python oferece duas operações primitivas diferentes baseadas em expressões regulares: matchverifica uma correspondência apenas no início da string, enquanto searchverifica uma correspondência em qualquer lugar da string (é o que o Perl faz por padrão).

Observe que isso matchpode diferir search mesmo quando se usa uma expressão regular iniciada por '^': '^'corresponde apenas no início da sequência ou no MULTILINEmodo também imediatamente após uma nova linha. A matchoperação " " será bem-sucedida apenas se o padrão corresponder no início da sequência, independentemente do modo, ou na posição inicial fornecida pelo pos argumento opcional, independentemente de uma nova linha preceder.

Agora, chega de conversa. Hora de ver algum código de exemplo:

# 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
nosklo
fonte
E as strings que contêm novas linhas?
Daryl Spitzer
26
Por que alguém usaria limitado, em matchvez de mais geral, searchentão? é por velocidade?
Alby
13
A correspondência @Alby é muito mais rápida que a pesquisa. Portanto, em vez de executar regex.search ("word"), você pode executar regex.match ((. *?) Word (. *?)) E obter muito desempenho se estiver trabalhando com milhões de amostras.
Ivan_bilan
20
Bem, isso é pateta. Por que chamá-lo match? É uma manobra inteligente para propagar as APIs com nomes não intuitivos para me forçar a ler a documentação? Eu ainda não vou fazer isso! Rebelde!
Sammaron 16/09/16
1
@ivan_bilan matchparece um pouco mais do fasterque pesquisar ao usar a mesma expressão regular, mas o seu exemplo parece errado de acordo com um teste de desempenho: stackoverflow.com/questions/180986/…
#
101

search ⇒ encontre algo em qualquer lugar da string e retorne um objeto correspondente.

match⇒ encontre algo no início da string e retorne um objeto correspondente.

Dhanasekaran Anbalagan
fonte
49

re.search procurar es para o padrão em toda a corda , enquanto re.matchse não procurar o padrão; caso contrário, não terá outra opção senão combiná- lo no início da string.

xilun
fonte
5
Por que combinar no início, mas não até o final da string ( fullmatchno phyton 3.4)?
perfil completo de Joao Carlos
49

A correspondência é muito mais rápida que a pesquisa; portanto, em vez de executar regex.search ("word"), você pode executar regex.match ((. *?) word (. *?)) e obter muito desempenho se estiver trabalhando com milhões de amostras.

Este comentário de @ivan_bilan sob a resposta aceita acima me fez pensar se esse hack realmente está acelerando alguma coisa, então vamos descobrir quantas toneladas de desempenho você realmente obterá.

Eu preparei o seguinte conjunto de testes:

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)

Fiz 10 medições (1M, 2M, ..., 10M palavras), o que me deu o seguinte gráfico:

plotagem de linha de speedtest de correspondência de pesquisa x regex

As linhas resultantes são surpreendentemente (na verdade, não surpreendentemente) retas. E a searchfunção é (ligeiramente) mais rápida, dada essa combinação de padrões específicos. A moral desse teste: evite otimizar demais o código.

Jeyekomon
fonte
12
+1 por realmente investigar as suposições por trás de uma declaração que deve ser aceita pelo valor nominal - obrigado.
Robert Dodier 30/10
De fato, o comentário de @ivan_bilan parece errado, mas a matchfunção ainda é mais rápida que a searchfunção se você comparar a mesma expressão regular. Você pode verificar no seu script, comparando re.search('^python', word)a re.match('python', word)(ou re.match('^python', word)o que é o mesmo, mas mais fácil de entender se você não ler a documentação e parece não afetar o desempenho)
baptx
@baptx Não concordo com a afirmação de que a matchfunção geralmente é mais rápida. Quanto matchmais rápido você deseja pesquisar no início da string, searchmais rápido quando você deseja pesquisar por toda a string. O que corresponde ao senso comum. É por isso que @ivan_bilan estava errado - ele costumava matchpesquisar por toda a string. É por isso que você está certo - você costumava matchpesquisar no início da string. Se você não concorda comigo, tente encontrar regex, pois matchisso é mais rápido re.search('python', word)e faz o mesmo trabalho.
Jeyekomon
@baptx Além disso, como nota de rodapé, o re.match('python') é marginalmente mais rápido que re.match('^python'). Tem que ser.
Jeyekomon 22/01/19
@ Jeyekomon sim, foi isso que eu quis dizer, a matchfunção é um pouco mais rápida se você deseja pesquisar no início de uma string (em comparação com o uso da searchfunção para encontrar uma palavra no início de uma string, re.search('^python', word)por exemplo). Mas acho isso estranho, se você disser à searchfunção para pesquisar no início de uma string, ela deve ser tão rápida quanto a matchfunção.
baptx
31

Você pode consultar o exemplo abaixo para entender o funcionamento re.matche a pesquisa.

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

re.matchretornará none, mas re.searchretornará abc.

ldR
fonte
3
Gostaria apenas de adicionar que a pesquisa retornará o objeto _sre.SRE_Match (ou Nenhum, se não for encontrado). Para obter 'abc', você precisa chamar t.group ()
SanD 1/17
30

A diferença é que re.match()engana qualquer pessoa acostumada à correspondência de expressões regulares Perl , grep ou sed , e re.search()não o faz. :-)

Mais sobriamente, como observa John D. Cook , re.match()"comporta-se como se todo padrão tivesse sido precedido". Em outras palavras, re.match('pattern')é igual re.search('^pattern'). Por isso, ancora o lado esquerdo de um padrão. Mas também não ancora o lado direito de um padrão: isso ainda requer uma terminação $.

Sinceramente, considerando o exposto, acho que re.match()deveria ser preterido. Eu estaria interessado em saber as razões pelas quais ele deveria ser mantido.

COD-REaD
fonte
4
"comporta-se como se todo padrão fosse ^ anexado." só é verdade se você não usar a opção multilinha. A declaração correta é "... tem \ A anexado"
JoelFan
14

re.match tenta corresponder a um padrão no início da string . re.search tenta corresponder o padrão em toda a sequência até encontrar uma correspondência.

cschol
fonte
3

Muito mais curto:

  • search varre toda a cadeia.

  • match varre apenas o início da string.

Seguindo Ex diz:

>>> a = "123abc"
>>> re.match("[a-z]+",a)
None
>>> re.search("[a-z]+",a)
abc
Sub-10
fonte