Quelle est la différence entre re.search et re.match?

527

Quelle est la différence entre les fonctions search()et match()dans le module Pythonre ?

J'ai lu la documentation ( documentation actuelle ), mais je ne m'en souviens jamais. Je continue de le chercher et de le réapprendre. J'espère que quelqu'un y répondra clairement avec des exemples pour que (peut-être) ça reste dans ma tête. Ou au moins, j'aurai un meilleur endroit pour revenir avec ma question et il faudra moins de temps pour la réapprendre.

Daryl Spitzer
la source

Réponses:

508

re.matchest ancré au début de la chaîne. Cela n'a rien à voir avec les nouvelles lignes, donc ce n'est pas la même chose que d'utiliser^ dans le motif.

Comme documentation re.match dit la :

Si zéro ou plusieurs caractères au début de la chaîne correspondent au modèle d'expression régulière, renvoyez unMatchObject instance . RevenirNone si la chaîne ne correspond pas au modèle; notez que ceci est différent d'une correspondance de longueur nulle.

Remarque: Si vous souhaitez rechercher une correspondance n'importe où dans la chaîne, utilisez search() plutôt.

re.searchrecherche la chaîne entière, comme le dit la documentation :

Parcourez la chaîne à la recherche d'un emplacement où le modèle d'expression régulière produit une correspondance et renvoyez une MatchObjectinstance correspondante . Retourne Nonesi aucune position dans la chaîne ne correspond au motif; notez que cela diffère de la recherche d'une correspondance de longueur nulle à un moment donné de la chaîne.

Donc, si vous devez faire correspondre au début de la chaîne, ou faire correspondre l'utilisation de la chaîne entière match. C'est plus rapide. Sinon, utilisez search.

La documentation a une section spécifique pour matchvssearch qui couvre également les chaînes multilignes:

Python propose deux opérations primitives différentes basées sur des expressions régulières: matchvérifie une correspondance uniquement au début de la chaîne, tandis que searchvérifie une correspondance n'importe où dans la chaîne (c'est ce que Perl fait par défaut).

Notez que cela matchpeut différer de search même lorsque vous utilisez une expression régulière commençant par '^': '^'ne correspond qu'au début de la chaîne, ou en MULTILINEmode également immédiatement après une nouvelle ligne. L' matchopération « » réussit que si le motif correspond au début de la chaîne, quel que soit le mode, ou à la position de départ donnée par l' pos argument facultatif , que la nouvelle ligne la précède ou non.

Maintenant, assez parlé. Il est temps de voir un exemple de code:

# 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
la source
Qu'en est-il des chaînes contenant des sauts de ligne?
Daryl Spitzer
26
Pourquoi quelqu'un utiliserait-il alors matchplutôt que plus général search? c'est pour la vitesse?
Alby
13
@Alby match est beaucoup plus rapide que la recherche, donc au lieu de faire regex.search ("word"), vous pouvez faire regex.match ((. *?) Word (. *?)) Et gagner des tonnes de performances si vous travaillez avec des millions d'échantillons.
ivan_bilan
20
Eh bien, c'est maladroit. Pourquoi l'appeler match? Est-ce une manœuvre intelligente de semer les API avec des noms non intuitifs pour me forcer à lire la documentation? Je ne le ferai toujours pas! Rebelle!
Sammaron
1
@ivan_bilan matchressemble un peu fasterà la recherche lorsque vous utilisez la même expression régulière, mais votre exemple semble incorrect selon un test de performance: stackoverflow.com/questions/180986/…
baptx
101

search ⇒ trouver quelque chose n'importe où dans la chaîne et renvoyer un objet match.

match⇒ trouver quelque chose au début de la chaîne et renvoyer un objet match.

Dhanasekaran Anbalagan
la source
49

re.search recherche le motif dans toute la chaîne , alors re.matchqu'il ne recherche pas le motif; s'il ne le fait pas, il n'a d'autre choix que de le faire correspondre au début de la chaîne.

xilun
la source
5
Pourquoi faire correspondre au début, mais pas jusqu'à la fin de la chaîne ( fullmatchen phyton 3.4)?
Smit Johnth
49

la correspondance est beaucoup plus rapide que la recherche, donc au lieu de faire regex.search ("mot") vous pouvez faire regex.match ((. *?) mot (. *?)) et gagner des tonnes de performances si vous travaillez avec des millions de échantillons.

Ce commentaire de @ivan_bilan sous la réponse acceptée ci-dessus m'a fait penser si un tel hack accélère réellement quelque chose, alors découvrons combien de tonnes de performances vous gagnerez vraiment.

J'ai préparé la suite de tests suivante:

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)

J'ai fait 10 mesures (1M, 2M, ..., 10M mots) qui m'ont donné l'intrigue suivante:

correspondance vs recherche regex speedtest tracé de ligne

Les lignes résultantes sont étonnamment (en fait pas si étonnamment) droites. Et la searchfonction est (légèrement) plus rapide compte tenu de cette combinaison de motifs spécifique. La morale de ce test: évitez de suroptimiser votre code.

Jeyekomon
la source
12
+1 pour avoir réellement enquêté sur les hypothèses derrière une déclaration censée être prise à leur valeur nominale - merci.
Robert Dodier
En effet le commentaire de @ivan_bilan semble faux mais la matchfonction est toujours plus rapide que la searchfonction si l'on compare la même expression régulière. Vous pouvez archiver votre script en comparant re.search('^python', word)à re.match('python', word)(ou re.match('^python', word)qui est le même mais plus facile à comprendre si vous ne lisez pas la documentation et ne semble pas affecter les performances)
baptx
@baptx Je ne suis pas d'accord avec l'affirmation selon laquelle la matchfonction est généralement plus rapide. Le matchest plus rapide lorsque vous souhaitez effectuer une recherche au début de la chaîne, le searchplus rapide lorsque vous souhaitez effectuer une recherche tout au long de la chaîne. Ce qui correspond au bon sens. C'est pourquoi @ivan_bilan avait tort - il cherchait matchtout au long de la chaîne. C'est pourquoi vous avez raison - vous matchcherchiez au début de la chaîne. Si vous n'êtes pas d'accord avec moi, essayez de trouver des expressions rationnelles car matchcela est plus rapide re.search('python', word)et fait le même travail.
Jeyekomon
@baptx Aussi, comme note de bas de page, le re.match('python') est légèrement plus rapide que re.match('^python'). Ça doit être.
Jeyekomon
@Jeyekomon oui c'est ce que je voulais dire, la matchfonction est un peu plus rapide si vous voulez chercher au début d'une chaîne (par rapport à utiliser la searchfonction pour trouver un mot au début d'une chaîne avec re.search('^python', word)par exemple). Mais je trouve cela bizarre, si vous dites à la searchfonction de rechercher au début d'une chaîne, elle devrait être aussi rapide que la matchfonction.
baptx
31

Vous pouvez vous référer à l'exemple ci-dessous pour comprendre le fonctionnement re.matchet la recherche.

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

re.matchreviendra none, mais re.searchreviendra abc.

ldR
la source
3
J'aimerais simplement ajouter que la recherche renverra l'objet _sre.SRE_Match (ou Aucun s'il n'est pas trouvé). Pour obtenir 'abc', vous devez appeler t.group ()
SanD
30

La différence est, re.match()induit en erreur toute personne habituée à l' appariement des expressions régulières Perl , grep ou sed , et re.search()ne le fait pas. :-)

Plus sobrement, comme le fait remarquer John D. Cook , re.match()"se comporte comme si chaque modèle avait ^ précédé". En d'autres termes, re.match('pattern')est égal à re.search('^pattern'). Il ancre donc le côté gauche d'un motif. Mais il n'ancre pas non plus le côté droit d'un motif: cela nécessite toujours une terminaison $.

Franchement, compte tenu de ce qui précède, je pense qu'il re.match()devrait être déconseillé. Je serais intéressé de connaître les raisons pour lesquelles il devrait être conservé.

CODE-REaD
la source
4
"se comporte comme si chaque motif avait ^ précédé." n'est vrai que si vous n'utilisez pas l'option multiligne. La déclaration correcte est "... has \ A prepended"
JoelFan
14

re.match tente de faire correspondre un modèle au début de la chaîne . re.search tente de faire correspondre le modèle dans la chaîne jusqu'à ce qu'il trouve une correspondance.

cschol
la source
3

Plus court:

  • search balaye toute la chaîne.

  • match analyse uniquement le début de la chaîne.

Ex suivant le dit:

>>> a = "123abc"
>>> re.match("[a-z]+",a)
None
>>> re.search("[a-z]+",a)
abc
U10-Forward
la source