Skip to content
Laviyx Learn

Try

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.

Intermediate6 min readUpdated
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:

Python
import re

text = "Call 98450-12345 or 99001-67890 today"
print(re.findall(r"\d{5}-\d{5}", text))
Output
['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#

PatternMatches
abcthe exact text "abc"
.any character except a newline
\d / \Da digit / a non-digit
\w / \Wa word character (letter, digit, _) / anything else
\s / \Swhitespace / non-whitespace
[aeiou]any one of these characters
[a-z], [0-9]a character in a range
[^0-9]any character not in the set
^ / $start / end of the string
a|ba or b

Quantifiers say how many times the previous item repeats:

QuantifierMeaning
*0 or more
+1 or more
?0 or 1 (optional)
{n}exactly n
{n,m}between n and m

The main functions#

FunctionReturns
re.findall(p, s)a list of all matches
re.search(p, s)the first match anywhere, or None
re.match(p, s)a match only at the start of the string, or None
re.fullmatch(p, s)a match only if the whole string matches
re.sub(p, repl, s)a new string with matches replaced
re.split(p, s)a list split at every match

search and match objects#

Python
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())
Output
False True
12 items 12 9
  • Matching is case-sensitive unless you pass re.IGNORECASE.
  • search returns a match object (or None, 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:

Python
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)
Output
2026-10-23 ERROR
2026-10-24 WARN

Named groups make patterns self-documenting:

Python
m = re.search(r"(?P<year>\d{4})-(?P<month>\d{2})", "Released 2026-10")
print(m.group("year"), m.group("month"), m.groupdict())
Output
2026 10 {'year': '2026', 'month': '10'}

Validating input#

Anchor the pattern with ^ and $ so the whole string must match:

Python
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)))
Output
asha@company.com True
ravi.k+test@mail.co.in True
bad-email False
x@y False

Replacing and splitting#

Python
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"))
Output
too many spaces here
PIN ######
['a', 'b', 'c ', 'd']

Compiling patterns#

If you use a pattern many times, compile it once:

Python
phone = re.compile(r"\+91[- ]?\d{10}")
print(phone.findall("Reach +91 9845012345 or +91-9900167890"))
Output
['+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:

Python
print(re.findall(r"<.+>", "<b>bold</b>"), re.findall(r"<.+?>", "<b>bold</b>"))
Output
['<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":

Python
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
Python
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]))
Output
[250, 1200, 75, 1525] 1525

The three prices add up to the stated total, so the data checks out.

Key takeaway#

Finished this lesson?