¿Cuál es la diferencia entre re.search y re.match?
Pregunta
¿Cuál es la diferencia entre las funciones search ()
y match ()
en Python re
module ?
He leído la documentación (< a href = "http://docs.python.org/2/library/re.html?highlight=matching%20searching#search-vs-match" rel = "noreferrer"> documentación actual ), pero Nunca parecen recordarlo. 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.
Solución
re.match
está anclado al comienzo de la cadena. Eso no tiene nada que ver con las líneas nuevas, por lo que no es lo mismo que usar ^
en el patrón.
Como la re.match documentación dice:
Si hay cero o más caracteres en la principio de cadena coincide con el patrón de expresión regular, devuelve un
MatchObject
correspondiente instancia. DevuelveNone
si la cadena no lo hace coincide con el patrón; nota que esto es diferente de una coincidencia de longitud cero.Nota: si quieres localizar una coincidencia en cualquier lugar de la cadena, use
search ()
en su lugar.
re.search
busca en toda la cadena, como la documentación dice :
Escanear a través de una cadena buscando un ubicación donde la expresión regular patrón produce una coincidencia, y devuelve un
MatchObject
correspondiente instancia. DevuelvaNone
si no hay una posición en el cadena coincide con el patrón; tenga en cuenta que esto es diferente de encontrar un partido de longitud cero en algún punto de la cadena.
Por lo tanto, si necesita hacer coincidir al principio de la cadena, o para hacer coincidir toda la cadena, use match
. Es mas rapido. De lo contrario, utilice search
.
La documentación tiene una sección específica para match
vs. search
que también cubre cadenas multilínea:
Python ofrece dos primitivas diferentes operaciones basadas en regular expresiones:
match
comprueba una coincidencia solo al principio de la cadena, mientras quesearch
busca una coincidencia en cualquier lugar en la cadena (esto es lo que Perl lo hace por defecto).Tenga en cuenta que
match
puede diferir desearch
incluso cuando se usa una expresión regular comenzando con'^'
:'^'
solo coincide al comienzo de la cadena, o en ModoMULTILINE
también inmediatamente siguiendo una nueva linea. El & # 8220;match
& # 8221; la operación tiene éxito solo si el patrón coincidencias en el inicio de la cadena independientemente del modo, o en el inicio Posición dada por el opcionalpos
argumento independientemente de si una La nueva línea lo precede.
Ahora, basta de hablar. Es hora de ver algún 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
Otros consejos
search
? encuentre algo en cualquier parte de la cadena y devuelva un objeto coincidente.
match
? encuentre algo al principio de la cadena y devuelva un objeto de coincidencia.
re.search
search es para el patrón a lo largo de la cadena , mientras que re.match
hace no buscar el patrón; si no lo hace, no tiene otra opción que hacer coincidir al comienzo de la cadena.
puede consultar el siguiente ejemplo para comprender el funcionamiento de re.match y re.search
a = "123abc"
t = re.match("[a-z]+",a)
t = re.search("[a-z]+",a)
re.match no devolverá ninguno, pero re.search devolverá abc.
La diferencia es que re.match ()
confunde a cualquiera que esté acostumbrado a Perl , grep o sed coincidencia de expresiones regulares, y re.search ()
no. :-)
Más sobrio, Como John D. Cook comenta , re.match ( )
" se comporta como si todos los patrones se hubieran precedido ^ " En otras palabras, re.match ('patrón')
es igual a re.search ('^ patrón')
. Así ancla el lado izquierdo de un patrón. Pero también no ancla el lado derecho de un patrón: que aún requiere un $
de terminación.
Francamente, dado lo anterior, creo que re.match ()
debería quedar en desuso. Me interesaría saber las razones por las que debería conservarse.
la coincidencia es mucho más rápida que la búsqueda, así que en lugar de hacer regex.search (" palabra ") puedes hacer regex.match ((. *?) word (. *?)) y ganar toneladas de rendimiento si eres trabajando con millones de muestras.
Este comentario de @ivan_bilan bajo el la respuesta aceptada arriba me hizo pensar si ese truco en realidad está acelerando algo, así que averigüemos cuántas toneladas de rendimiento realmente ganará.
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 trama:
Las líneas resultantes son sorprendentemente (en realidad no tan sorprendentemente) rectas. Y la función search
es (ligeramente) más rápida dada esta combinación de patrones específica. La moraleja de esta prueba: Evite sobre-optimizar su código.
re.match intenta hacer coincidir un patrón al principio de la cadena . re.search intenta hacer coincidir el patrón a lo largo de la cadena hasta que encuentre una coincidencia.
Mucho más corto:
search
analiza toda la cadena.match
Hace solo el comienzo de la cadena.
El siguiente Ex lo dice:
>>> a = "123abc"
>>> re.match("[a-z]+",a)
None
>>> re.search("[a-z]+",a)
abc