Quelle est la différence entre les fonctions search()
et match()
du module Python re
?
J'ai lu le documentation ( documentation actuelle ), mais je ne semble jamais m'en souvenir. Je continue à avoir à le chercher et à le réapprendre. J'espère que quelqu'un y répondra clairement par des exemples afin que (peut-être) cela me reste dans la tête. Ou du moins, ma question me permettra de revenir plus facilement et il faudra moins de temps pour la réapprendre.
re.match
est ancré au début de la chaîne. Cela n’a rien à voir avec les nouvelles lignes, ce n’est donc pas la même chose que d’utiliser ^
dans le motif.
Comme le documentation re.match dit:
Si zéro ou plusieurs caractères au début de la chaîne correspondent au modèle d'expression régulière, renvoyez une instance
MatchObject
correspondante. RenvoieNone
si la chaîne ne correspond pas au modèle; notez que cela diffère d'une correspondance de longueur nulle.Remarque: Si vous souhaitez localiser une correspondance n'importe où dans la chaîne, utilisez plutôt
search()
.
re.search
recherche dans toute la chaîne, comme la documentation le dit :
Parcourez la chaîne à la recherche d'un emplacement où le modèle d'expression régulière produit une correspondance et renvoyez une instance
MatchObject
correspondante. RenvoieNone
si 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 avez besoin de faire correspondre au début de la chaîne, ou pour faire correspondre toute la chaîne, utilisez match
. C'est plus rapide. Sinon, utilisez search
.
La documentation a une section spécifique pour match
vs. search
qui couvre également les chaînes multilignes:
Python propose deux opérations primitives différentes basées sur des expressions régulières:
match
recherche une correspondance uniquement au début de la chaîne, tandis quesearch
vérifie la présence d'une correspondance n'importe où dans la chaîne (c'est ce que Perl fait par défaut).Notez que
match
peut différer desearch
même si vous utilisez une expression régulière commençant par'^'
:'^'
ne correspond qu'au début de la chaîne ou àMULTILINE
. mode également immédiatement après une nouvelle ligne. L’opération “match
” réussit uniquement si le modèle correspond au début de la chaîne quel que soit le mode ou à la position de départ indiquée par l’argument optionnelpos
, qu’il soit précédé ou non d’une nouvelle ligne.
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
search
⇒ trouver quelque chose n'importe où dans la chaîne et retourner un objet match.
match
⇒ trouvez quelque chose au début de la chaîne = et retournez un objet correspondant.
re.search
recherche es pour le motif dans toute la chaîne, alors que re.match
ne fait pas de recherche le motif; si ce n'est pas le cas, il n'a pas d'autre choix que de faire correspondre au début de la chaîne.
la correspondance est beaucoup plus rapide que la recherche. Ainsi, au lieu de faire regex.search ("Word"), vous pouvez le faire avec regex.match ((. *?) Word (. *?)) et gagner des tonnes de performances si vous travaillez avec des millions de fichiers. des é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 quoi que ce soit, alors voyons combien de tonnes de performances vous allez vraiment gagner.
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:
Les lignes résultantes sont étonnamment droites (en fait pas étonnamment). Et la fonction search
est (légèrement) plus rapide étant donné cette combinaison de motif spécifique. La morale de ce test: Évitez d’optimiser votre code.
La différence est la suivante: re.match()
trompe quiconque est habitué à Perl , grep , ou sed la correspondance d'expression régulière, et re.search()
ne le fait pas. :-)
Plus sobrement, Comme le fait remarquer John D. Cook , re.match()
"se comporte comme si chaque motif avait été préposé". En d'autres termes, re.match('pattern')
est égal à re.search('^pattern')
. Donc, il ancre le côté gauche d'un motif. Mais cela n'empêche pas non plus le côté droit d'un motif: qui nécessite toujours une terminaison $
.
Franchement, étant donné ce qui précède, je pense que re.match()
devrait être obsolète. Je serais intéressé de connaître les raisons pour lesquelles il devrait être conservé.
Vous pouvez vous référer à l'exemple ci-dessous pour comprendre le fonctionnement de re.match
et re.search
a = "123abc"
t = re.match("[a-z]+",a)
t = re.search("[a-z]+",a)
re.match
retournera none
, mais re.search
retournera abc
.
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 tout au long de la chaîne jusqu'à ce qu'il trouve une correspondance.
Plus court:
search
balaye l'intégralité de la chaîne.
match
Fait seulement le début de la chaîne.
Après Ex le dit:
>>> a = "123abc"
>>> re.match("[a-z]+",a)
None
>>> re.search("[a-z]+",a)
abc