Was ist der Unterschied zwischen re.search und re.match?

527

Was ist der Unterschied zwischen den Funktionen search()und match()im Python- reModul ?

Ich habe die Dokumentation gelesen ( aktuelle Dokumentation ), aber ich scheine mich nie daran zu erinnern. Ich muss es immer wieder nachschlagen und neu lernen. Ich hoffe, dass jemand es klar mit Beispielen beantwortet, damit es (vielleicht) in meinem Kopf bleibt. Oder zumindest habe ich einen besseren Ort, um mit meiner Frage zurückzukehren, und es wird weniger Zeit dauern, sie erneut zu lernen.

Daryl Spitzer
quelle

Antworten:

508

re.matchist am Anfang der Zeichenfolge verankert. Das hat nichts mit Zeilenumbrüchen zu tun, daher ist es nicht dasselbe wie ^im Muster.

In der Dokumentation zu re.match heißt es:

Wenn null oder mehr Zeichen am Anfang der Zeichenfolge mit dem Muster des regulären Ausdrucks übereinstimmen, geben Sie eine entsprechende MatchObjectInstanz zurück. Rückgabe, Nonewenn die Zeichenfolge nicht mit dem Muster übereinstimmt; Beachten Sie, dass sich dies von einer Übereinstimmung mit der Länge Null unterscheidet.

Hinweis: Wenn Sie eine Übereinstimmung an einer beliebigen Stelle in der Zeichenfolge suchen möchten, verwenden Sie search() stattdessen.

re.searchdurchsucht die gesamte Zeichenfolge, wie in der Dokumentation angegeben :

Durchsuchen Sie die Zeichenfolge nach einer Stelle, an der das Muster des regulären Ausdrucks eine Übereinstimmung erzeugt, und geben Sie eine entsprechende MatchObjectInstanz zurück. Rückgabe, Nonewenn keine Position in der Zeichenfolge mit dem Muster übereinstimmt; Beachten Sie, dass dies anders ist als das Finden einer Übereinstimmung mit der Länge Null an einem bestimmten Punkt in der Zeichenfolge.

Wenn Sie also am Anfang der Zeichenfolge übereinstimmen müssen oder die gesamte Zeichenfolge verwenden möchten, verwenden Sie match. Es ist schneller. Andernfalls verwenden search.

Die Dokumentation enthält einen speziellen Abschnitt für matchvs.search , der auch mehrzeilige Zeichenfolgen abdeckt:

Python bietet zwei verschiedene primitive Operationen basierend auf regulären Ausdrücken: matchprüft , ob ein Spiel erst am Anfang der Zeichenfolge, während searchprüft , ob ein Spiel irgendwo im String (das ist , was Perl standardmäßig der Fall ist).

Beachten Sie, dass dies auch bei Verwendung eines regulären Ausdrucks, der mit : beginnt , matchabweichen kann. Übereinstimmungen nur am Anfang der Zeichenfolge oder im Modus auch unmittelbar nach einer neuen Zeile. Die Operation " " ist nur erfolgreich, wenn das Muster unabhängig vom Modus am Anfang der Zeichenfolge oder an der durch das optionale Argument angegebenen Startposition übereinstimmt, unabhängig davon, ob eine neue Zeile davor steht.search'^''^'MULTILINEmatchpos

Jetzt genug geredet. Zeit, einen Beispielcode zu sehen:

# 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
quelle
Was ist mit Zeichenfolgen, die Zeilenumbrüche enthalten?
Daryl Spitzer
26
Warum sollte jemand dann matcheher begrenzte als allgemeinere verwenden search? ist es für die Geschwindigkeit?
Alby
13
@Alby Match ist viel schneller als die Suche. Anstatt also regex.search ("word") auszuführen, können Sie regex.match ((. *?) Word (. *?)) Ausführen und eine Menge Leistung erzielen, wenn Sie mit arbeiten Millionen von Proben.
ivan_bilan
20
Nun, das ist doof. Warum es nennen match? Ist es ein kluges Manöver, die APIs mit nicht intuitiven Namen zu versehen, um mich zum Lesen der Dokumentation zu zwingen? Ich werde es immer noch nicht tun! Rebell!
Sammaron
1
@ivan_bilan matchsieht ein bisschen fasterwie Suche aus, wenn der gleiche reguläre Ausdruck verwendet wird, aber Ihr Beispiel scheint laut einem Leistungstest falsch zu sein: stackoverflow.com/questions/180986/…
Taufe
101

search ⇒ Suchen Sie irgendwo in der Zeichenfolge etwas und geben Sie ein Übereinstimmungsobjekt zurück.

match⇒ Suchen Sie etwas am Anfang der Zeichenfolge und geben Sie ein Übereinstimmungsobjekt zurück.

Dhanasekaran Anbalagan
quelle
49

re.search Such es für das Muster in der gesamten Zeichenfolge , während re.matchsie nicht sucht das Muster; wenn dies nicht der Fall, es hat keine andere Wahl , als passen es der Zeichenfolge am Anfang.

xilun
quelle
5
Warum am Anfang übereinstimmen, aber nicht bis zum Ende der Zeichenfolge ( fullmatchin Phyton 3.4)?
Smit Johnth
49

Die Übereinstimmung ist viel schneller als die Suche. Anstatt also regex.search ("word") auszuführen, können Sie regex.match ((. *?) word (. *?)) ausführen und eine Menge Leistung erzielen, wenn Sie mit Millionen von arbeiten Proben.

Dieser Kommentar von @ivan_bilan unter der oben akzeptierten Antwort hat mich zum Nachdenken gebracht, ob ein solcher Hack tatsächlich etwas beschleunigt. Lassen Sie uns also herausfinden, wie viele Tonnen Leistung Sie wirklich gewinnen werden.

Ich habe die folgende Testsuite vorbereitet:

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)

Ich habe 10 Messungen durchgeführt (1M, 2M, ..., 10M Wörter), die mir die folgende Darstellung gaben:

Übereinstimmung gegen Suche Regex Speedtest Liniendiagramm

Die resultierenden Linien sind überraschend (eigentlich nicht so überraschend) gerade. Und die searchFunktion ist bei dieser speziellen Musterkombination (etwas) schneller . Die Moral dieses Tests: Vermeiden Sie eine Überoptimierung Ihres Codes.

Jeyekomon
quelle
12
+1 für die tatsächliche Untersuchung der Annahmen hinter einer Aussage, die zum Nennwert angenommen werden soll - danke.
Robert Dodier
Der Kommentar von @ivan_bilan sieht zwar falsch aus, aber die matchFunktion ist immer noch schneller als die searchFunktion, wenn Sie denselben regulären Ausdruck vergleichen. Sie können durch den Vergleich in Ihrem Skript überprüfen re.search('^python', word)zu re.match('python', word)(oder re.match('^python', word)was das gleiche , aber leichter zu verstehen , wenn Sie nicht in der Dokumentation lesen Sie und scheint nicht die Leistung zu beeinträchtigen)
baptx
@baptx Ich bin nicht einverstanden mit der Aussage, dass die matchFunktion im Allgemeinen schneller ist. Je matchschneller Sie suchen, wenn Sie am Anfang der Zeichenfolge searchsuchen möchten, desto schneller, wenn Sie in der gesamten Zeichenfolge suchen möchten . Welches entspricht dem gesunden Menschenverstand. Deshalb hat sich @ivan_bilan geirrt - er hat immer matchin der gesamten Zeichenfolge gesucht. Deshalb haben Sie Recht - Sie haben früher matcham Anfang der Zeichenfolge gesucht. Wenn Sie mit mir nicht einverstanden sind, versuchen Sie, Regex zu finden, denn matchdas ist schneller als re.search('python', word)und erledigt den gleichen Job.
Jeyekomon
Auch als Fußnote @baptx, das re.match('python') ist geringfügig schneller als re.match('^python'). Es muss sein.
Jeyekomon
@Jeyekomon Ja, das habe ich gemeint. Die matchFunktion ist etwas schneller, wenn Sie am Anfang einer Zeichenfolge suchen möchten (im Vergleich zur Verwendung der searchFunktion, um beispielsweise ein Wort am Anfang einer Zeichenfolge zu finden re.search('^python', word)). Aber ich finde das seltsam. Wenn Sie der searchFunktion sagen , dass sie am Anfang eines Strings suchen soll, sollte sie genauso schnell sein wie die matchFunktion.
Taufe
31

Sie können sich auf das folgende Beispiel beziehen, um die Funktionsweise re.matchund Forschung zu verstehen

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

re.matchwird zurückkehren none, wird aber re.searchzurückkehren abc.

ldR
quelle
3
Wenn Sie nur hinzufügen möchten, dass die Suche das Objekt _sre.SRE_Match zurückgibt (oder None, wenn es nicht gefunden wird). Um 'abc' zu erhalten, müssen Sie t.group ()
SanD
30

Der Unterschied besteht darin, dass re.match()jeder, der an Perl- , Grep- oder Sed- Übereinstimmungen mit regulären Ausdrücken gewöhntre.search() ist, irregeführt wird und dies nicht tut. :-)

Nüchterner, wie John D. Cook bemerkt , re.match()"verhält sich so, als ob jedes Muster vorangestellt wäre." Mit anderen Worten, re.match('pattern')gleich re.search('^pattern'). So verankert es die linke Seite eines Musters. Aber es verankert auch nicht die rechte Seite eines Musters: Das erfordert immer noch eine Beendigung $.

Ehrlich gesagt denke ich, re.match()sollte veraltet sein. Es würde mich interessieren, warum es beibehalten werden sollte.

CODE-REaD
quelle
4
"verhält sich so, als hätte jedes Muster vorangestellt." ist nur wahr, wenn Sie die mehrzeilige Option nicht verwenden. Die korrekte Aussage ist "... hat \ A vorangestellt"
JoelFan
14

re.match versucht, ein Muster am Anfang der Zeichenfolge abzugleichen . re.search versucht, das Muster in der gesamten Zeichenfolge abzugleichen, bis eine Übereinstimmung gefunden wird.

cschol
quelle
3

Viel kürzer:

  • search scannt die gesamte Zeichenfolge.

  • match scannt nur den Anfang der Zeichenfolge.

Folgende Ex sagt es:

>>> a = "123abc"
>>> re.match("[a-z]+",a)
None
>>> re.search("[a-z]+",a)
abc
U10-Vorwärts
quelle