Regular expressions
Part of the free LogicWiz Python course, Pack B: College Semester Pack. The examples and practice run in the app.
The fest registration sheet has 800 rows typed by students: "98765 43210", "+91-9876543210", "riya@gmail,com". Checking each by hand is impossible. A regular expression checks a pattern in one line.
You'll learn to
- Read and write patterns with `\d`, `\w`, `[...]`, `{n}`, `+`, `*`, `?`, `^` and `
Regular expressions: Python Course | LogicWiz - Use `re.search`, `re.fullmatch`, `re.findall` and `re.sub`, and groups
- Validate Indian mobile numbers, emails and PIN codes
Learn
A pattern language
A regular expression (regex) describes a shape of text. Always write it as a raw string r"...".
| Token | Matches |
|---|---|
\d |
a digit 0-9 |
\w |
a letter, digit or _ |
\s |
a space, tab or newline |
. |
any character |
[6-9] |
one of 6, 7, 8, 9 |
[A-Z] |
a capital letter |
x+ x* x? |
one or more, zero or more, optional |
x{6} x{2,4} |
exactly 6, 2 to 4 |
^ $ |
start, end of the text |
(...) |
a group you can pull out |
\. |
a real dot |
re.search finds the first match
import re
msg = "Hi, this is Riya. Call me on 9876543210 after 5 pm."
m = re.search(r"[6-9]\d{9}", msg)
if m:
print("found:", m.group())
print("at position", m.start())
print(re.search(r"\d{12}", msg))
re.search scans the text and returns a Match object, or None if nothing matches. Always check for None before calling .group().
re.findall gets them all
import re
chat = """Aarav: my no is 9876543210
Sneha: mine is +91 8123456789, office 080-2345678
Kabir: PIN 560038, email [email protected]"""
print(re.findall(r"[6-9]\d{9}", chat))
print(re.findall(r"\b[1-9]\d{5}\b", chat))
print(re.findall(r"[\w.+-]+@[\w-]+(?:\.[\w-]+)+", chat))
\b is a word boundary: it stops \d{6} from matching six digits from the middle of a phone number. (?:...) groups without capturing.
Groups pull out the parts
import re
m = re.search(r"([\w.]+)@([\w.]+)", "Write to [email protected] today")
print(m.group(0))
print(m.group(1), "|", m.group(2))
marks = "Riya: 87, Kabir: 92, Sneha: 78"
pairs = re.findall(r"(\w+): (\d+)", marks)
print(pairs)
print({name: int(score) for name, score in pairs})
group(0) is the whole match; group(1), group(2) are the brackets in order. With groups, findall returns tuples of the groups.
re.sub replaces
import re
print(re.sub(r"\s+", " ", " Riya Sharma CSE ").strip())
print(re.sub(r"[6-9]\d{9}", "XXXXXXXXXX", "Call 9876543210 or 8123456789"))
print(re.sub(r"(\d{2})\d{6}(\d{2})", r"\1******\2", "Paid from 9876543210"))
In the replacement, \1 and \2 put the groups back. This is how apps show your number as 98******10.
Validating: search vs fullmatch
import re
pin = r"[1-9]\d{5}"
for text in ["560038", "056003", "5600381", "PIN 560038"]:
print(f"{text:<11} search={bool(re.search(pin, text))!s:<5} fullmatch={bool(re.fullmatch(pin, text))}")
search is happy if the pattern appears anywhere, so "5600381" passes. To check that the whole text is a PIN, use re.fullmatch (or ^...$ with search).
Always use raw strings. In a normal string, "\b" is a backspace character, so re.search("\bcat\b", s) silently matches nothing. r"\bcat\b" passes the backslashes to re untouched. And remember . means any character: to match a real dot in gmail.com, write \..
Lab mapping. "Check whether a phone number / email is valid using regex" is a VTU Python lab program (its textbook, Automate the Boring Stuff, has a full regex chapter), and regex appears in the Anna, JNTU, AKTU and Mumbai syllabi as well.
Viva: "match vs search vs fullmatch?" (start only / anywhere / whole string) "What does findall return with groups?" (tuples) "Why r""?" "Greedy vs non-greedy?" (.* takes as much as it can, .*? as little).
In one line
Write regex as r"..."; search finds anywhere, fullmatch validates the whole text, findall lists all (tuples with groups), sub replaces (\1 reuses a group).