Python course menu
Python Regular Expressions (re): Search, Match, Extract and Replace Text
Learn Python regular expressions with the re module: pattern syntax, findall, search, match, groups and named groups, sub and split, flags, validating emails and phone numbers, and greedy vs lazy matching.
On this page
A regular expression (regex) is a pattern that describes text: "five digits, a dash, five more digits", or "something that looks like an email address". Python's re module uses these patterns to find, check, extract and replace text, tasks that would take many lines with ordinary string methods.
A first example#
Find all phone numbers in a sentence:
import re
text = "Call 98450-12345 or 99001-67890 today"
print(re.findall(r"\d{5}-\d{5}", text))['98450-12345', '99001-67890']\d means "a digit" and {5} means "exactly five times". Patterns are written as raw strings (r"...") so backslashes reach the regex engine unchanged.
Pattern building blocks#
Quantifiers say how many times the previous item repeats:
The main functions#
search and match objects#
print(bool(re.search(r"python", "I love Python")),
bool(re.search(r"python", "I love Python", re.IGNORECASE)))
m = re.search(r"(\d+) items", "Order of 12 items placed")
print(m.group(0), m.group(1), m.start())False True
12 items 12 9- Matching is case-sensitive unless you pass
re.IGNORECASE. searchreturns a match object (orNone, so always check before using it).group(0)is the whole match;group(1)is the part inside the first( ).
Groups: extracting parts#
Parentheses capture parts of a match. With findall, each match becomes a tuple of groups:
log = "2026-10-23 ERROR db timeout; 2026-10-24 WARN slow query"
for date_, level in re.findall(r"(\d{4}-\d{2}-\d{2}) (ERROR|WARN)", log):
print(date_, level)2026-10-23 ERROR
2026-10-24 WARNNamed groups make patterns self-documenting:
m = re.search(r"(?P<year>\d{4})-(?P<month>\d{2})", "Released 2026-10")
print(m.group("year"), m.group("month"), m.groupdict())2026 10 {'year': '2026', 'month': '10'}Validating input#
Anchor the pattern with ^ and $ so the whole string must match:
pattern = r"^[\w.+-]+@[\w-]+\.[\w.]+$"
for email in ["asha@company.com", "ravi.k+test@mail.co.in", "bad-email", "x@y"]:
print(email, bool(re.match(pattern, email)))asha@company.com True
ravi.k+test@mail.co.in True
bad-email False
x@y FalseReplacing and splitting#
print(re.sub(r"\s+", " ", "too many spaces here"))
print(re.sub(r"\d", "#", "PIN 560001"))
print(re.split(r"[,;]\s*", "a, b;c ,d"))too many spaces here
PIN ######
['a', 'b', 'c ', 'd']Compiling patterns#
If you use a pattern many times, compile it once:
phone = re.compile(r"\+91[- ]?\d{10}")
print(phone.findall("Reach +91 9845012345 or +91-9900167890"))['+91 9845012345', '+91-9900167890'][- ]? allows an optional dash or space. \+ matches a literal plus sign, because + on its own means "one or more".
Greedy vs lazy#
Quantifiers are greedy: they match as much as possible. Add ? to make them lazy:
print(re.findall(r"<.+>", "<b>bold</b>"), re.findall(r"<.+?>", "<b>bold</b>"))['<b>bold</b>'] ['<b>', '</b>']Common mistakes#
Practice#
Practice exercise
Extract every rupee amount from this text as integers, then print the list and the sum of all amounts except the final "Total":
text = "Prices: ₹250, ₹1,200 and ₹75. Total ₹1,525."Show hint
Use a group after the ₹ sign: r"₹([\d,]+)". Remove commas before converting with int().
Show solution
import re
text = "Prices: ₹250, ₹1,200 and ₹75. Total ₹1,525."
amounts = [int(a.replace(",", "")) for a in re.findall(r"₹([\d,]+)", text)]
print(amounts, sum(amounts[:-1]))[250, 1200, 75, 1525] 1525The three prices add up to the stated total, so the data checks out.
Key takeaway#
Finished this lesson?