Python Series track

Week 09 · Intermediate Track

Week 9 — Regular Expressions

Unlock powerful text-matching with regular expressions. Learn pattern syntax, groups, lookahead/lookbehind, and use re.findall, re.sub, and re.fullmatch for text extraction and cleaning.

Intermediate Track2 min readFree lesson

Level: Intermediate | Prerequisite: Week 8

Learning Goals

  • Use the re module for pattern matching
  • Know commonly used metacharacters (\d, \w, +, *, ?)
  • Utilize group capturing
  • Use replacement (re.sub)

1. Basic Usage

import re

#Search (First Match)
m = re.search(r"\d{3}-\d{4}-\d{4}", "Phone: 010-1234-5678")
print(m.group())   # 010-1234-5678

#Find All
print(re.findall(r"\d+", "5 apples, 3 bananas"))   # ['5', '3']

#Match Status
if re.match(r"^\d+$", "12345"):
    print("Numbers Only")

#Replace
print(re.sub(r"\d+", "?", "5 apples, 3 bananas"))   #? apples, ? bananas

2. Commonly Used Metacharacters

Pattern Meaning
. Any single character
\d Digit ([0-9])
\D Non-digit
\w Alphanumeric, underscore
\s Whitespace
^ Start
$ End
[abc] One of a, b, c
[^abc] Not a, b, c
[a-z] Range

3. Quantifiers

Pattern Meaning
* 0 or more times
+ 1 or more times
? 0 or 1 time
{n} Exactly n times
{n,m} n to m times
? (after quantifier) Minimum matching (non-greedy)

4. Group Capturing

Group by (...). Extract by m.group(N) or m.groups().

log = "ERROR 2026-05-09 14:32 Authentication Failed"
m = re.match(r"(\w+) (\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}) (.+)", log)
print(m.groups())   #('ERROR', '2026-05-09', '14:32', 'Authentication Failed')

#Naming Group
m = re.match(r"(?P<level>\w+) (?P<date>\d{4}-\d{2}-\d{2})", log)
print(m.group("level"), m.group("date"))

5. raw string

Prevent escape collisions. Regex always recommend r"...".

#For regular strings, \d should be interpreted as \\d to be safe
re.findall(r"\d+", text)    #Recommended
re.findall("\\d+", text)    #Same but confusing

6. Compile

If using the same pattern multiple times, pre-compile.

email_re = re.compile(r"[\w.]+@[\w.]+\.\w+")
emails = email_re.findall("Contact: [email protected], [email protected]")
print(emails)

Key Examples (examples/)

File Content
01_basic.py search, findall
02_meta.py Meta character
03_groups.py Group capture
04_sub_compile.py sub, compile

⚠️ Common Mistakes

  1. Missing escape — Not added inside r → \d → d. Always r"...".
  2. Greedy matching — <.+> matches the entire <a><b>. Minimal matching is <.+?>.
  3. match vs search — match only the first time, search anywhere.
  4. Regex too complex — If readability drops, just branch in code.

❓ FAQ

Q1. How to debug regex? A. Test patterns on sites like https://regex101.com.

Q2. Is regex slow? A. Generally fast. But catastrophic backtracking patterns are very slow.

Q3. Perfect email validation pattern? A. Exact RFC validation is very long. For practical level, use [\w.+-]+@[\w-]+\.[\w.-]+.

📝 Exercises (exercises/)

  • exercise1.md — Extract emails
  • exercise2.md — Validate mobile numbers
  • exercise3.md — Extract only ERROR from logs

Next Week

Week 10. Comprehensive practice

Example files

The runnable files used in this lesson. Copy them into your own project and experiment.

examples/01_basic.pyPython
import re

#Search (first match only)
m = re.search(r"\d{3}-\d{4}-\d{4}", "Phone number: 010-1234-5678")
print(m.group())

#Find All
print(re.findall(r"\d+", "5 apples, 3 bananas, 12 grapes"))

#Match status (match from the beginning)
if re.match(r"^\d+$", "12345"):
    print("Consists of numbers only")

#Match result information
m = re.search(r"hello", "say hello world")
print(m.start(), m.end(), m.span())
examples/02_meta.pyPython
import re

text = "abc123 XYZ hello ___"

print(re.findall(r"\d", text))      #Number
print(re.findall(r"\w+", text))     #Word (number/alphabet/underscore/Unicode)
print(re.findall(r"\s+", text))     #Space
print(re.findall(r"[A-Z]+", text))  #Uppercase letter
print(re.findall(r"[a-z]+", text))      #Lowercase letter
print(re.findall(r"^\w+", text))    #Start
print(re.findall(r"\w+$", text))    #End (leading and trailing spaces not removed, so result is empty)
examples/03_groups.pyPython
import re

log = "ERROR 2026-05-09 14:32 User authentication failed"

m = re.match(r"(\w+) (\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}) (.+)", log)
print(m.groups())
print(m.group(1), m.group(2))

#Naming Group
m = re.match(
    r"(?P<level>\w+) (?P<date>\d{4}-\d{2}-\d{2}) (?P<time>\d{2}:\d{2}) (?P<msg>.+)",
    log,
)
print(m.group("level"))
print(m.group("date"))
print(m.groupdict())
examples/04_sub_compile.pyPython
import re

#Replace
print(re.sub(r"\d+", "?", "5 rooms, 3 beds"))

#Replace with a function
def double(m):
    return str(int(m.group()) * 2)

print(re.sub(r"\d+", double, "5 rooms, 3 beds"))   #10 rooms, 6 beds

#Compile — when using the same pattern multiple times
email_re = re.compile(r"[\w.+-]+@[\w-]+\.[\w.-]+")
print(email_re.findall("[email protected] / [email protected] / not_an_email"))

Assignment

Goal

Extract all email addresses from a long text.

Input Example

Please contact me. [email protected] or [email protected]
Company email: [email protected] is also okay.

Output Example

['[email protected]', '[email protected]', '[email protected]']

Task 2. Validate Mobile Phone Numbers

Goal

Write function is_valid_phone(s) -> bool.

Format

  • 010-XXXX-XXXX (X is a number)
  • Starts with 010
  • Hyphen required

Test Cases

assert is_valid_phone("010-1234-5678")
assert not is_valid_phone("011-1234-5678")
assert not is_valid_phone("010 1234 5678")
assert not is_valid_phone("010-12345-678")

Task 3. Extract only ERROR from Logs

Goal

Extract only the ERROR lines from log From-file/string and output only the time.

Input Example

INFO 2026-05-09 10:00 Start
ERROR 2026-05-09 10:05 Authentication Failed
WARN 2026-05-09 10:07 Slow
ERROR 2026-05-09 10:30 DB Connection Lost
INFO 2026-05-09 10:35 Restart

Output Example

[ERROR] 10:05
[ERROR] 10:30
Show the reference solution

Try the assignment yourself first — comparing your attempt with a working solution is where most of the learning happens.

solution1.pyPython
import re

text = """Please contact me. [email protected] or [email protected]
Company email: [email protected] is also fine."""

emails = re.findall(r"[\w.+-]+@[\w-]+\.[\w.-]+", text)
print(emails)
solution2.pyPython
import re

PATTERN = re.compile(r"^010-\d{4}-\d{4}$")

def is_valid_phone(s):
    return bool(PATTERN.match(s))

print(is_valid_phone("010-1234-5678"))   # True
print(is_valid_phone("011-1234-5678"))   # False
print(is_valid_phone("010 1234 5678"))   # False
print(is_valid_phone("010-12345-678"))   # False
print(is_valid_phone("01012345678"))     # False
solution3.pyPython
import re

LOG = """INFO 2026-05-09 10:00 Start
ERROR 2026-05-09 10:05 Authentication Failed
WARN 2026-05-09 10:07 Slow
ERROR 2026-05-09 10:30 DB Connection Lost
INFO 2026-05-09 10:35 Restart"""

pattern = re.compile(r"^ERROR \d{4}-\d{2}-\d{2} (\d{2}:\d{2})", re.MULTILINE)
for time in pattern.findall(LOG):
    print(f"[ERROR] {time}")

Learn this lesson with a mentor

Work through the Python Series track on your own, or join a guided cohort at our Pitampura campus and online.

Call NowEnroll Now