search, match, findall and sub
18 min · Intermediate
Need help? Ask a tutor on WhatsApp (opens in a new tab)A pattern is only half the job. The re module has a function for each question: is it there, where is it, how many times, and what should it become?
search, match and fullmatch
Match object is what a successful search returns. It holds the matched text and its position: group(), groups(), start(), end() and span().
All three return a match object or None. search looks anywhere in the text, match only at the start, and fullmatch needs the whole text to fit.
import re
print(re.search(r"cat", "concat"))print(re.match(r"cat", "concat"))print(re.fullmatch(r"cat", "cat"))Example 1 · Three functions, one text
import re
text = "cat sat"print(re.search(r"sat", text).span())print(re.match(r"sat", text))print(re.fullmatch(r"cat sat", text) is not None)(4, 7) None True
What this code does
searchfindssatat positions 4 to 7.matchfails because the text does not start withsat.fullmatchaccepts it because the pattern covers the whole text.
Always test the result before you call group(). On None it raises AttributeError.
findall and finditer
findall returns every match as a list. With no groups it holds the matched strings; with one group it holds that group; with several groups it holds tuples. finditer yields match objects one at a time.
import re
print(re.findall(r"\d+", "a1b22c333"))print(re.findall(r"(\w)=(\d)", "a=1 b=2"))Example 2 · findall and finditer
import re
log = "id=7 id=15 id=203"print(re.findall(r"id=(\d+)", log))for m in re.finditer(r"id=(\d+)", log): print(m.group(1), m.start())['7', '15', '203'] 7 0 15 5 203 11
What this code does
- With one group,
findallreturns only the group text, notid=. finditeralso tells us where each match starts.
Use finditer when you need positions or named groups for each hit.
sub and split
Substitution is replacing every part of a text that matches a pattern with new text. re.sub does it and returns a new string; the original is unchanged.
re.sub(pattern, replacement, text) returns new text with every match replaced. The replacement can use \1 for group 1, or be a function that receives each match. re.split cuts text where the pattern matches.
import re
print(re.sub(r"\s+", " ", "a b \n c"))print(re.split(r"[,;]\s*", "x, y;z"))Example 3 · sub with a group and a function
import re
print(re.sub(r"(\w+) (\w+)", r"\2 \1", "hello world"))
def double(m): return str(int(m.group()) * 2)
print(re.sub(r"\d+", double, "Pen 20, Book 150"))world hello Pen 40, Book 300
What this code does
\2 \1swaps the two captured words.- When the replacement is a function, it gets each match and returns the new text.
Strings are immutable, so sub returns a new string and leaves the old one alone.
Flags and compiled patterns
Flag is an option passed to a regex function that changes how the pattern matches, such as re.IGNORECASE to ignore letter case or re.MULTILINE to anchor each line.
A flag changes how a pattern behaves: re.IGNORECASE ignores case, re.MULTILINE lets ^ and $ work per line. re.compile builds the pattern once so you can name it and reuse it.
import re
PHONE = re.compile(r"\d{5}-\d{5}")print(PHONE.findall("98765-43210 and 11111-22222"))Example 4 · Flags and compile
import re
print(re.findall(r"cat", "Cat cat CAT", re.IGNORECASE))text = "one\ntwo\nthree"print(re.findall(r"^t\w+", text, re.MULTILINE))pin = re.compile(r"^[1-9]\d{5}$")print(bool(pin.search("560001")))['Cat', 'cat', 'CAT'] ['two', 'three'] True
What this code does
IGNORECASEfinds all three spellings.MULTILINElets^match at the start of every line.- The compiled
pincan be reused in many places.
A compiled pattern has the same methods: search, findall, sub and the rest.
Next step
Check your understanding
11 quick questions