Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
107: Matching and Searching with re
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
There are no comments for now.