hayaliv

hayaliv / Hi! Python / Level 1

Regular expressions, the basics

Find, extract and replace text patterns with re.search, re.findall and re.sub.

Hi! Python · Level 1: Files and data · Checked against the Python 3.12 documentation · Updated 2026-10-17

Think of it like this

A regular expression is like a stencil you lay over a page. Only the words that fit the holes show through.

Where the analogy stops being true. A stencil has a fixed shape, while a regex is written by you and can fit more or less than you meant.

What to know

Example

import re

EMAIL = r"[\w.]+@[\w.]+\.\w+"
reply = "Thanks! Reach me at jane.doe@example.com or sam@corp.io, call 5pm."
m = re.search(EMAIL, reply)
print(m.group())
print(re.findall(EMAIL, reply))
print(re.sub(EMAIL, "<EMAIL>", reply))
m2 = re.search(r"([\w.]+)@([\w.]+\.\w+)", reply)
print(m2.group(1), "|", m2.group(2))
print(re.findall(r"([\w.]+)@([\w.]+\.\w+)", reply))

It prints:

jane.doe@example.com
['jane.doe@example.com', 'sam@corp.io']
Thanks! Reach me at <EMAIL> or <EMAIL>, call 5pm.
jane.doe | example.com
[('jane.doe', 'example.com'), ('sam', 'corp.io')]

Predict, then check

1. What does this print?

import re

print(re.search(r"\d+", "no digits here"))
Show the answer
None

There is no digit anywhere, so search returns None.

2. What does this print?

import re

print(re.sub(r"\d", "#", "call 555-1234"))
Show the answer
call ###-####

Every single digit is replaced by #, and the dash is left alone.

3. What does this print?

import re

print(re.findall(r"[\w.]+@[\w.]+\.\w+", "ping a@b or c@d.org"))
Show the answer
['c@d.org']

The pattern needs a dot after the @ part, so a@b is missed. This shows a simple regex can miss things.

4. What does this print?

import re

try:
    re.search(r"\d", "abc").group()
except AttributeError:
    print("no match")
Show the answer
no match

search returned None, and None has no group method, so AttributeError is raised.

Try it

Write mask_emails(text). Replace every email-like piece (use the pattern r"[\w.]+@[\w.]+\.\w+") with <EMAIL> and return the new text.

def mask_emails(text):
    return text
Show a solution
import re

def mask_emails(text):
    return re.sub(r"[\w.]+@[\w.]+\.\w+", "<EMAIL>", text)

Common mistake

re.search returns None when nothing matches, so calling .group() on the result can fail. Test the result first with if m:, because a match object is always true.

In a small-language-model project

Before putting real cold-email replies into a training file, you may want to mask email addresses with re.sub. A regex may catch only some personal data, so treat it as a first pass and still look at samples.

Sources

Each quote below appears word for word on the cited page of the official Python documentation (version 3.12).

Step through this lesson in the Hi! Python desktop

← CSVDataclasses →