Skip to Content
Course content

107: Matching and Searching with re

Click on the "Edit" button in the top corner of the screen to edit your slide content.

A few years ago, I was tasked with cleaning up a legacy database migration. We had thousands of "notes" fields where users had haphazardly typed in order numbers, tracking IDs, and reference codes. My boss wanted a list of every tracking number that followed a very specific format: two letters, a dash, and then six digits. I spent the first hour trying to use .split() and .startswith(), but the data was too messy. Some notes started with the ID, some had it buried in the middle of a sentence, and some had it surrounded by parentheses. I was losing my mind until I stopped fighting the string methods and just used the re module. It turned an hour of frustration into about four lines of code.

In Python, the re module is your go-to for Regular Expressions. While basic string methods like .find() are great for simple matches, re allows you to search for patterns. It's the difference between looking for the exact word "Apple" and looking for "any word that starts with a capital letter and ends with a number."

The Tug-of-War Between match and search

One of the most common mistakes I see developers make when they first touch the re module is confusing re.match() with re.search(). They seem identical, but they behave very differently.

re.match() is strict. It only checks if the pattern exists at the beginning of the string. If your pattern is in the middle or at the end, re.match() will return None. On the other hand, re.search() scans through the entire string to find the first location where the pattern produces a match.

import re

text = "Order number: ORD-5521"

# This returns None because the string doesn't START with 'ORD'
fail = re.match(r'ORD-\d+', text) 

# This finds the pattern regardless of where it sits
success = re.search(r'ORD-\d+', text)

if success:
    print(f"Found it: {success.group()}")

Notice the r before the string? That denotes a "raw string." In regex, backslashes (like \d for digits) are common. Without the r, Python might try to interpret \n as a newline instead of a regex symbol. Just get in the habit of always using raw strings for your patterns; it'll save you a lot of debugging headaches.

Collecting Every Occurrence with findall

Sometimes you don't just want the first match—you want every single one. This is where re.findall() comes in. Unlike search, which returns a "match object" (which is why we have to call .group() to see the text), findall returns a simple list of strings.

Imagine you're scraping a page for email addresses. You don't want just the first one; you want them all. Here is how that looks in practice:

import re

log_data = "Error at 10:15: User 402 failed. Error at 10:22: User 109 failed."
user_ids = re.findall(r'User \d+', log_data)

print(user_ids) # Output: ['User 402', 'User 109']

It's clean, efficient, and avoids the need for a for loop and a manual list append. Regex is a bit of a secret language—once you get the syntax, you'll feel like you have a superpower, but don't beat yourself up if you have to look up a cheat sheet every five minutes. I still do.

Isolating Data with Capturing Groups

Often, you need to match a pattern to find a piece of data, but you don't actually want the "boilerplate" part of that pattern in your final result. For example, if you're looking for User 402, you probably only care about the 402.

You achieve this using parentheses (), which create "capturing groups." When you use groups with re.search(), you can access the specific part of the match by its index.

import re

text = "Payment received from account: ACC-99821"
# We match the whole thing, but 'capture' only the digits
match = re.search(r'account: ACC-(\d+)', text)

if match:
    # group(0) is the whole match, group(1) is the first set of parentheses
    print(f"Full match: {match.group(0)}") 
    print(f"Account ID only: {match.group(1)}")

By wrapping \d+ in parentheses, we've told Python: "I need the account: ACC- part to be there for the match to be valid, but I only want to extract the digits."




📋 Practical Task

Exercise: Extracting Product SKUs from a Warehouse Manifest

You have been given a raw string containing a manifest of shipped items. Each item has a SKU (Stock Keeping Unit) that follows a strict format: three uppercase letters, a hyphen, and four numbers (e.g., TSH-1234). Some lines contain noise, and some contain multiple SKUs.

Your task: Write a script that uses the re module to find all SKUs in the manifest and store them in a list. Then, for the first SKU found, use a capturing group to extract only the numeric part of that SKU.

manifest = """
SHIPMENT 101:
- Item: Blue T-Shirt [TSH-4421]
- Item: Red Socks [SKS-1029]
- Note: Package damaged for TSH-8810.
- Item: Green Hat [HTS-2210]
- Shipping Label: REF-99001 (Ignore this one)
"""

Expected Output:
Full list: ['TSH-4421', 'SKS-1029', 'TSH-8810', 'HTS-2210']
First ID number: 4421

Rating
0 0

There are no comments for now.

to be the first to leave a comment.