What is the difference between the search() and match() functions in the Python re module?
I've read the Python 2 documentation (Python 3 documentation), but I never seem to remember it.
What is the difference between the search() and match() functions in the Python re module?
I've read the Python 2 documentation (Python 3 documentation), but I never seem to remember it.
re.match is anchored at the beginning of the string. That has nothing to do with newlines, so it is not the same as using ^ in the pattern.
As the re.match documentation says:
If zero or more characters at the beginning of string match the regular expression pattern, return a corresponding
MatchObjectinstance. ReturnNoneif the string does not match the pattern; note that this is different from a zero-length match.Note: If you want to locate a match anywhere in string, use
search()instead.
re.search searches the entire string, as the documentation says:
Scan through string looking for a location where the regular expression pattern produces a match, and return a corresponding
MatchObjectinstance. ReturnNoneif no position in the string matches the pattern; note that this is different from finding a zero-length match at some point in the string.
So if you need to match at the beginning of the string, or to match the entire string use match. It is faster. Otherwise use search.
The documentation has a specific section for match vs. search that also covers multiline strings:
Python offers two different primitive operations based on regular expressions:
matchchecks for a match only at the beginning of the string, whilesearchchecks for a match anywhere in the string (this is what Perl does by default).Note that
matchmay differ fromsearcheven when using a regular expression beginning with'^':'^'matches only at the start of the string, or inMULTILINEmode also immediately following a newline. The “match” operation succeeds only if the pattern matches at the start of the string regardless of mode, or at the starting position given by the optionalposargument regardless of whether a newline precedes it.
Now, enough talk. Time to see some example 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
match rather than more general search then? is it for speed?match? Is it a clever maneuver to seed the API's with unintuitive names to force me to read the documentation? I still won't do it! Rebel!match looks a bit faster than search when using the same regular expression but your example seems wrong according to a performance test: stackoverflow.com/questions/180986/…MULTILINE unspecified, is match the same as search (produce the same result)?match is much faster than search, so instead of doing regex.search("word") you can do regex.match((.*?)word(.*?)) and gain tons of performance if you are working with millions of samples.
This comment from @ivan_bilan under the accepted answer above got me thinking if such hack is actually speeding anything up, so let's find out how many tons of performance you will really gain.
I prepared the following test suite:
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)
I made 10 measurements (1M, 2M, ..., 10M words) which gave me the following plot:
As you can see, searching for the pattern 'python' is faster than matching the pattern '(.*?)python(.*?)'.
Python is smart. Avoid trying to be smarter.
match function is still faster than the search function if you compare the same regular expression. You can check in your script by comparing re.search('^python', word) to re.match('python', word) (or re.match('^python', word) which is the same but easier to understand if you don't read the documentation and seems not to affect the performance)match function is generally faster. The match is faster when you want to search at the beginning of the string, the search is faster when you want to search throughout the string. Which corresponds with the common sense. That's why @ivan_bilan was wrong - he used match to search throughout the string. That's why you are right - you used match to search at the beginning of the string. If you disagree with me, try to find regex for match that is faster than re.search('python', word) and does the same job.re.match('python') is marginally faster than re.match('^python'). It has to be.match function is a bit faster if you want to search at the beginning of a string (compared to using search function to find a word at the beginning of a string with re.search('^python', word) for example). But I find this weird, if you tell the search function to search at the beginning of a string, it should be as fast as the match function.re.search searches for the pattern throughout the string, whereas re.match does not search the pattern; if it does not, it has no other choice than to match it at start of the string.
fullmatch in phyton 3.4)?The difference is, re.match() misleads anyone accustomed to Perl, grep, or sed regular expression matching, and re.search() does not. :-)
More soberly, As John D. Cook remarks, re.match() "behaves as if every pattern has ^ prepended." In other words, re.match('pattern') equals re.search('^pattern'). So it anchors a pattern's left side. But it also doesn't anchor a pattern's right side: that still requires a terminating $.
Frankly given the above, I think re.match() should be deprecated. I would be interested to know reasons it should be retained.
You can refer the below example to understand the working of re.match and re.search
a = "123abc"
t = re.match("[a-z]+",a)
t = re.search("[a-z]+",a)
re.match will return none, but re.search will return abc.
Much shorter:
search scans through the whole string.
match scans only the beginning of the string.
Following Ex says it:
>>> a = "123abc"
>>> re.match("[a-z]+",a)
None
>>> re.search("[a-z]+",a)
abc
re.match is anchored at the beginning of a string, while re.search scans through the entire string. So in the following example, x and y match the same thing.
x = re.match('pat', s) # <--- already anchored at the beginning of string
y = re.search('\Apat', s) # <--- match at the beginning
If a string doesn't contain line breaks, \A and ^ are essentially the same; the difference shows up in multiline strings. In the following example, re.match will never match the second line, while re.search can with the correct regex (and flag).
s = "1\n2"
re.match('2', s, re.M) # no match
re.search('^2', s, re.M) # match
re.search('\A2', s, re.M) # no match <--- mimics `re.match`
There's another function in re, re.fullmatch() that scans the entire string, so it is anchored both at the beginning and the end of a string. So in the following example, x, y and z match the same thing.
x = re.match('pat\Z', s) # <--- already anchored at the beginning; must match end
y = re.search('\Apat\Z', s) # <--- match at the beginning and end of string
z = re.fullmatch('pat', s) # <--- already anchored at the beginning and end
Based on Jeyekomon's answer (and using their setup), using the perfplot library, I plotted the results of timeit tests that looks into:
re.search "mimics" re.match? (first plot)re.match "mimics" re.search? (second plot)Note that the last pattern doesn't produce the same output (because re.match is anchored at the beginning of a string.)
The first plot shows match is faster if search is used like match. The second plot supports @Jeyekomon's answer and shows search is faster if match is used like search. The last plot shows there's very little difference between the two if they scan for the same pattern.
Code used to produce the performance plot.
import re
from random import choices
from string import ascii_lowercase
import matplotlib.pyplot as plt
from perfplot import plot
patterns = [
[re.compile(r'\Aword'), re.compile(r'word')],
[re.compile(r'word'), re.compile(r'(.*?)word')],
[re.compile(r'word')]*2
]
fig, axs = plt.subplots(1, 3, figsize=(20,6), facecolor='white')
for i, (pat1, pat2) in enumerate(patterns):
plt.sca(axs[i])
perfplot.plot(
setup=lambda n: [''.join(choices(ascii_lowercase, k=10)) for _ in range(n)],
kernels=[lambda lst: [*map(pat1.search, lst)], lambda lst: [*map(pat2.match, lst)]],
labels= [f"re.search(r'{pat1.pattern}', w)", f"re.match(r'{pat2.pattern}', w)"],
n_range=[2**k for k in range(24)],
xlabel='Length of list',
equality_check=None
)
fig.suptitle('re.match vs re.search')
fig.tight_layout();
searchwill search to the end of the string off in the distance.