¿Cuál es la diferencia entre re.search y re.match?


527

¿Cuál es la diferencia entre las funciones search()y match()en el módulo Pythonre ?

He leído la documentación ( documentación actual ), pero parece que nunca la recuerdo. Sigo teniendo que buscarlo y volver a aprenderlo. Espero que alguien responda claramente con ejemplos para que (tal vez) se quede en mi cabeza. O al menos tendré un lugar mejor para regresar con mi pregunta y me llevará menos tiempo volver a aprenderla.

Respuestas:


508

re.matchestá anclado al comienzo de la cadena. Eso no tiene nada que ver con las nuevas líneas, por lo que no es lo mismo que usar ^en el patrón.

Como dice la documentación re.match :

Si cero o más caracteres al comienzo de la cadena coinciden con el patrón de expresión regular, devuelve una MatchObjectinstancia correspondiente . Regrese Nonesi la cadena no coincide con el patrón; tenga en cuenta que esto es diferente de una coincidencia de longitud cero.

Nota: Si desea ubicar una coincidencia en cualquier lugar de la cadena, use search() en su lugar.

re.searchbusca en toda la cadena, como dice la documentación :

Explore a través de una cadena buscando una ubicación donde el patrón de expresión regular produzca una coincidencia y devuelva una MatchObjectinstancia correspondiente . Devuelve Nonesi ninguna posición en la cadena coincide con el patrón; tenga en cuenta que esto es diferente de encontrar una coincidencia de longitud cero en algún punto de la cadena.

Entonces, si necesita hacer coincidir al comienzo de la cadena, o para que coincida con toda la cadena, use match. Es mas rapido. De lo contrario uso search.

La documentación tiene una sección específica para matchvs.search que también cubre cadenas multilínea:

Python ofrece dos operaciones primitivas diferentes basadas en expresiones regulares: matchbusca una coincidencia solo al comienzo de la cadena, mientras que searchbusca una coincidencia en cualquier parte de la cadena (esto es lo que hace Perl por defecto).

Tenga en cuenta que matchpuede diferir search incluso cuando se usa una expresión regular que comienza con '^': '^'coincide solo al comienzo de la cadena, o en el MULTILINEmodo también inmediatamente después de una nueva línea. La matchoperación " " tiene éxito solo si el patrón coincide al comienzo de la cadena, independientemente del modo, o en la posición inicial dada por el pos argumento opcional, independientemente de si una nueva línea lo precede.

Ahora, basta de hablar. Es hora de ver un código de ejemplo:

# 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

¿Qué pasa con las cadenas que contienen nuevas líneas?
Daryl Spitzer

26
¿Por qué alguien usaría limitado en matchlugar de más general searchentonces? es por velocidad?
Alby

13
@Alby match es mucho más rápido que la búsqueda, así que en lugar de hacer regex.search ("word") puedes hacer regex.match ((. *?) Word (. *?)) Y ganar toneladas de rendimiento si trabajas con millones de muestras
ivan_bilan

20
Bueno, eso es tonto. ¿Por qué llamarlo match? ¿Es una maniobra inteligente sembrar las API con nombres no intuitivos para obligarme a leer la documentación? ¡Todavía no lo haré! ¡Rebelde!
Sammaron

1
@ivan_bilan matchparece un poco más fasterque buscar cuando se usa la misma expresión regular, pero su ejemplo parece incorrecto según una prueba de rendimiento: stackoverflow.com/questions/180986/…
baptx

101

search ⇒ encuentre algo en cualquier lugar de la cadena y devuelva un objeto de coincidencia.

match⇒ encuentre algo al comienzo de la cadena y devuelva un objeto de coincidencia.


49

re.search busca el patrón en toda la cadena , mientras re.matchque no busca el patrón; si no es así, no tiene otra opción que hacerla coincidir al comienzo de la cadena.


55
¿Por qué coincidir al inicio, pero no hasta el final de la cadena ( fullmatchen phyton 3.4)?
Smit Johnth

49

la coincidencia es mucho más rápida que la búsqueda, por lo que en lugar de hacer regex.search ("word") puedes hacer regex.match ((. *?) word (. *?)) y ganar toneladas de rendimiento si trabajas con millones de muestras

Este comentario de @ivan_bilan bajo la respuesta aceptada arriba me hizo pensar si tal truco realmente está acelerando algo, así que descubramos cuántas toneladas de rendimiento realmente obtendrás.

Preparé el siguiente conjunto de pruebas:

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)

Hice 10 mediciones (1M, 2M, ..., 10M palabras) que me dieron la siguiente gráfica:

diagrama de línea de prueba de expresión vs. búsqueda de coincidencia vs. búsqueda

Las líneas resultantes son sorprendentemente (en realidad no tan sorprendentemente) rectas. Y la searchfunción es (ligeramente) más rápida dada esta combinación de patrones específicos. La moraleja de esta prueba: evite optimizar demasiado su código.


12
+1 por investigar realmente los supuestos detrás de una declaración que debe tomarse al pie de la letra, gracias.
Robert Dodier

De hecho, el comentario de @ivan_bilan parece incorrecto, pero la matchfunción sigue siendo más rápida que la searchfunción si se compara la misma expresión regular. Se puede comprobar en la secuencia de comandos mediante la comparación re.search('^python', word)de re.match('python', word)(o re.match('^python', word)lo que es lo mismo, pero más fácil de entender si usted no lee la documentación y parece no afectar el rendimiento)
baptx

@baptx No estoy de acuerdo con la afirmación de que la matchfunción es generalmente más rápida. El matches más rápido cuando desea buscar al principio de la cadena, searches más rápido cuando desea buscar en toda la cadena. Lo que corresponde con el sentido común. Es por eso que @ivan_bilan estaba equivocado: solía matchbuscar en toda la cadena. Es por eso que tienes razón: solías matchbuscar al principio de la cadena. Si no está de acuerdo conmigo, trate de encontrar expresiones regulares para matchque sea más rápido re.search('python', word)y haga el mismo trabajo.
Jeyekomon

@baptx Además, como nota al pie, el re.match('python') es marginalmente más rápido que re.match('^python'). Tiene que ser.
Jeyekomon

@Jeyekomon sí, eso es lo que quise decir, la matchfunción es un poco más rápida si desea buscar al principio de una cadena (en comparación con el uso de la searchfunción para encontrar una palabra al principio de una cadena con, re.search('^python', word)por ejemplo). Pero me parece extraño, si le dice a la searchfunción que busque al principio de una cadena, debería ser tan rápida como la matchfunción.
baptx

31

Puede consultar el siguiente ejemplo para comprender el funcionamiento re.matchy la búsqueda.

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

re.matchvolverá none, pero re.searchvolverá abc.


3
Solo me gustaría agregar que la búsqueda devolverá el objeto _sre.SRE_Match (o Ninguno si no se encuentra). Para obtener 'abc', debe llamar a t.group ()
SanD

30

La diferencia es que re.match()engaña a cualquiera que esté acostumbrado a Perl , grep o sed coincidencia de expresiones regulares, y re.search()no lo hace. :-)

Más sobriamente, como señala John D. Cook , re.match()"se comporta como si cada patrón ^ hubiera antepuesto". En otras palabras, re.match('pattern')es igual re.search('^pattern'). Por lo tanto, ancla el lado izquierdo de un patrón. Pero tampoco ancla el lado derecho de un patrón: eso todavía requiere una terminación $.

Francamente, dado lo anterior, creo que re.match()debería ser obsoleto. Me interesaría saber las razones por las que debería conservarse.


44
"se comporta como si cada patrón hubiera ^ antepuesto". solo es cierto si no utiliza la opción multilínea. La declaración correcta es "... has \ A
prepended

14

re.match intenta hacer coincidir un patrón al comienzo de la cadena . re.search intenta hacer coincidir el patrón en toda la cadena hasta que encuentre una coincidencia.


3

Mucho más corto:

  • search escanea toda la cadena.

  • match escanea solo el comienzo de la cadena.

Siguiente Ex lo dice:

>>> a = "123abc"
>>> re.match("[a-z]+",a)
None
>>> re.search("[a-z]+",a)
abc
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.