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
111: Substitution with re.sub
I was digging through some legacy server logs this morning, and I ran into a classic headache. The logs were a mess—some entries used dashes for dates, some used slashes, and some had weird whitespace. I needed to scrub these dates out for a privacy report, and my first instinct was to just use .replace().
The limits of simple replacement
I started with something like this, trying to normalize the date separators before removing them:
log_entry = "Error at 2023-10-12 14:00:01 - User failed login. See 2023/10/12 for details."
clean_entry = log_entry.replace("-", "/").replace(" ", "_")
print(clean_entry)
# Output: Error at 2023/10/12_14:00:01_/_User_failed_login._See_2023/10/12_for_details.
Yeah, that's a disaster. .replace() is great when you know exactly which character you're hunting, but it's a blunt instrument. It doesn't understand patterns. It just sees a dash and kills it, regardless of whether that dash is part of a date or just a separator in the sentence. I don't want to replace every dash; I only want to replace things that look like dates.
Testing the waters with re.sub
This is where re.sub() comes in. The "sub" is short for substitution. Instead of a static string, I can give it a regex pattern. I'll try to target those dates (YYYY-MM-DD or YYYY/MM/DD) and swap them for a generic [DATE] tag.
import re
log_entry = "Error at 2023-10-12 14:00:01 - User failed login. See 2023/10/12 for details."
# I'll try a simple pattern for 4 digits, a separator, 2 digits, a separator, 2 digits
pattern = r"\d{4}[-/]\d{2}[-/]\d{2}"
result = re.sub(pattern, "[DATE]", log_entry)
print(result)
# Output: Error at [DATE] 14:00:01 - User failed login. See [DATE] for details.
That's much better. In one move, I handled both the dashes and the slashes. The logic here is simple: re.sub(pattern, replacement, original_string). It scans the string and every time the pattern hits, it swaps it out.
Dealing with messy whitespace
But wait, looking closer at the logs, some of the entries have accidental double spaces or tabs that make the output look jagged. I want to collapse any sequence of two or more whitespace characters into a single space. I'll try to chain another re.sub call.
messy_log = "Error at [DATE] 14:00:01 - User failed login."
# \s matches any whitespace, + means "one or more"
# But I want "two or more", so I'll use {2,}
clean_log = re.sub(r"\s{2,}", " ", messy_log)
print(clean_log)
# Output: Error at [DATE] 14:00:01 - User failed login.
I love this because it's surgical. I'm not just replacing every space with a space (which would be pointless); I'm specifically targeting the "clumps" of whitespace. It keeps the single spaces intact while cleaning up the noise.
Stopping the substitution early
One last thing: sometimes I only want to mask the first date found in a line—maybe the first date is the event time, and the second date is a reference that needs to stay. I noticed re.sub has an optional count argument. Let's see what happens when I use it.
log_entry = "Event: 2023-10-12. Reference: 2023-11-01."
# Only replace the first occurrence
result = re.sub(r"\d{4}-\d{2}-\d{2}", "[DATE]", log_entry, count=1)
print(result)
# Output: Event: [DATE]. Reference: 2023-11-01.
Exactly what I needed. By default, count is 0, which means "replace everything." Setting it to 1 makes it stop after the first match. It's a small detail, but it prevents you from over-cleaning your data when precision matters.
📋 Practical Task
The Product SKU Standardizer
You are working with a database of product SKUs that were entered by different people over five years. Some use underscores, some use hyphens, and some use dots. To make the database searchable, you need to standardize all SKUs to use only hyphens.
Your Task: Write a function called standardize_sku(sku) that takes a string and replaces any sequence of one or more underscores, dots, or hyphens with a single hyphen.
Test Case:
Input: "PROD__123...456--ABC_XYZ"
Expected Output: "PROD-123-456-ABC-XYZ"
There are no comments for now.