Python Tutorial menu

Python Regular Expressions

A regular expression (regex) is a small pattern that describes text, and Python's re module uses it to find, check and replace text.

Why Regex?

String methods like find() and replace() work with exact text. But what if you want "any mobile number" or "every price in this message"? A regex can describe a *kind* of text, not just one fixed word.

Example

python
import re

message = "Call Ali on 0300-1234567 or Sara on 0321-7654321 after 5 pm."
phones = re.findall(r"03\d{2}-\d{7}", message)
print(phones)
Output
['0300-1234567', '0321-7654321']

The pattern 03\d{2}-\d{7} means: "03, then two digits, then a dash, then seven digits".

Always write patterns as raw strings with an r in front, like r"\d+". Otherwise Python may treat the backslash as an escape character before the regex even sees it.

The Building Blocks

PatternMatches
.Any one character (except a new line)
\dA digit 0-9
\wA letter, digit or underscore
\sA space, tab or new line
\D, \W, \SThe opposite of the three above
[abc]One of a, b or c
[a-z]Any small letter
[^0-9]Anything that is not a digit
^ / $Start / end of the text
\bEdge of a word

How Many Times?

PatternMeaning
*0 or more
+1 or more
?0 or 1 (optional)
{3}Exactly 3
{2,5}From 2 to 5

The Main Functions

FunctionWhat it does
re.search(p, text)Finds the first match anywhere, or None
re.match(p, text)Checks only at the start of the text
re.fullmatch(p, text)The whole text must match
re.findall(p, text)A list of all matches
re.sub(p, new, text)Replaces every match
re.split(p, text)Splits the text at every match

Example

python
import re

text = "Order #4521: 3 shirts for Rs 2,400 and 1 cap for Rs 650"

m = re.search(r"#\d+", text)
print(m.group(), m.start())

print(re.findall(r"\d+", text))
print(re.findall(r"Rs [\d,]+", text))
print(re.split(r"\s*and\s*", text))
print(re.sub(r"\d", "*", "PIN 4821"))
Output
#4521 6
['4521', '3', '2', '400', '1', '650']
['Rs 2,400', 'Rs 650']
['Order #4521: 3 shirts for Rs 2,400', '1 cap for Rs 650']
PIN ****

Checking Input With fullmatch()

fullmatch() is the right choice when you want to validate something, because it fails if there is any extra text.

Example

python
import re

def valid_mobile(number):
    return re.fullmatch(r"(\+92|0)3\d{2}-?\d{7}", number) is not None

for n in ["03001234567", "0300-1234567", "+923001234567", "0300-12345", "03001234567abc"]:
    print(n, valid_mobile(n))
Output
03001234567 True
0300-1234567 True
+923001234567 True
0300-12345 False
03001234567abc False

(\+92|0) means "+92 or 0". The + needs a backslash because a plain + means "one or more". -? makes the dash optional.

Groups: Taking Parts Out

Round brackets make a group. You can read each group on its own. Named groups (?P<name>...) make the code easier to read.

Example

python
import re

email = "ayesha.khan@workownix.com"
m = re.fullmatch(r"([\w.]+)@([\w-]+\.\w+)", email)
print(m.group(1))
print(m.group(2))

line = "2026-10-15 Invoice KHI-0042 total 18500"
p = r"(?P<date>\d{4}-\d{2}-\d{2}) Invoice (?P<inv>[A-Z]+-\d+) total (?P<amount>\d+)"
m = re.search(p, line)
print(m["date"], m["inv"], int(m["amount"]) + 500)
print(m.groupdict())
Output
ayesha.khan
workownix.com
2026-10-15 KHI-0042 19000
{'date': '2026-10-15', 'inv': 'KHI-0042', 'amount': '18500'}

Groups always return strings, so use int() before doing maths.

Cleaning Text With sub()

Example

python
import re

messy = "  Hello    Ali,   your   order   is   ready!  "
print(re.sub(r"\s+", " ", messy).strip())

phone = "0300 123-45 67"
print(re.sub(r"\D", "", phone))

print(re.sub(r"(\d{4})-(\d{2})-(\d{2})", r"\3/\2/\1", "Due 2026-11-30"))
Output
Hello Ali, your order is ready!
03001234567
Due 30/11/2026

In the last line \3/\2/\1 puts the groups back in a new order, turning a date from year-month-day into day/month/year.

Flags and compile()

Flags change how a pattern behaves. If you use the same pattern many times, re.compile() saves it as an object.

Example

python
import re

print(re.findall(r"python", "Python, PYTHON and python", flags=re.IGNORECASE))

price = re.compile(r"Rs\.?\s?(\d+)")
for msg in ["Rs 500 only", "Now Rs.350!", "Free"]:
    m = price.search(msg)
    print(m.group(1) if m else "no price")
Output
['Python', 'PYTHON', 'python']
500
350
no price

Regex is powerful but hard to read. Keep patterns short, add a comment that explains them, and test them with a few good and bad examples, just like we did above.

Exercise

Exercise

What does re.findall(r"\d+", "Room 12, floor 3") return?

Learn Python with a teacher

Join the Python Programming course at Workownix, online or in Orangi Town, Karachi, and get a certificate.

See the course Ask on WhatsApp