Q&A library Python

What is the difference between re.match, re.search and re.findall in Python?

Python Intermediate reregexstrings

Short answer

match only checks the start of the string, search scans anywhere for the first match, and findall returns every match as a list. Mixing up match and search is the usual source of confusion.

The short version

re.match only looks at the start of the string, re.search scans the whole string for the first match anywhere, and re.findall returns every non-overlapping match as a list. The classic mistake is using match when you meant search, then wondering why a pattern that clearly appears in the text is not found.

The three in action

import re

re.match(r"\d+", "abc123")     # None, no digits at the start
re.search(r"\d+", "abc123")    # matches "123" anywhere
re.findall(r"\d+", "a1b22c333") # ['1', '22', '333'], every run of digits

match failed because the string does not begin with digits. search found the digits later in the string. findall returned all three digit groups.

This is the distinction to internalise. match is anchored to the beginning, as if the pattern started with ^. search has no such anchor and finds the first match wherever it is. If you want "does this pattern appear anywhere", use search. Use match only when you specifically mean "does the string start with this".

match and search return a match object

Both return a match object (or None), not the text. Get the matched string with .group(), and check for a match with a truth test or by comparing to None.

m = re.search(r"\d+", "abc123")
if m:
    print(m.group())   # "123"

Testing if m: works because a match object is truthy and None is falsy. Calling .group() on a None result raises AttributeError, which is a common error when you forget to check for no match.

findall returns strings, and groups change it

findall returns a list of strings directly, which is convenient. But if your pattern has capture groups, findall returns the groups instead of the whole match, which surprises people.

re.findall(r"(\w)(\d)", "a1b2")   # [('a', '1'), ('b', '2')], tuples of groups

If you want the whole matches even while using groups, use finditer and call .group() on each, or make the groups non-capturing with (?:...).

finditer for many matches with detail

When you need each match's position or groups, finditer yields match objects rather than plain strings.

for m in re.finditer(r"\d+", "a1b22"):
    print(m.group(), m.start())

This gives both the text and where it was found, which findall cannot.

Compile when reusing a pattern

If you use the same pattern many times, compile it once with re.compile and call methods on the result. It reads cleanly and avoids recompiling the pattern on every call, which matters in a loop over many strings.

digits = re.compile(r"\d+")
digits.search("abc123")

Need this solved on your own data?

The library is free and always will be. When the problem is bigger than an answer, we take on the work.

Start a project