AI Skill Report Card
Using Python Regex
Using Python Regex (re module)
Quick Start14 / 15
Pythonimport re # Compile once, reuse often pattern = re.compile(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b') text = "Contact: alice@example.com or bob@test.org" matches = pattern.findall(text) # ['alice@example.com', 'bob@test.org'] # Single search m = re.search(r'\d+', "Order #4521") if m: print(m.group()) # '4521'
Recommendation▾
Add an example showing a bad/incorrect regex outcome (e.g., greedy match failure) alongside the fix for contrast
Workflow13 / 15
Progress:
- Step 1: Define the exact string shape you need to match (be explicit about anchors, boundaries, optional parts)
- Step 2: Choose the right function (
match,search,findall,finditer,sub,split) - Step 3: Write the pattern using raw strings (
r"...") to avoid escape confusion - Step 4: Use named groups
(?P<name>...)for clarity when extracting multiple fields - Step 5: Compile the pattern with
re.compile()if reused in a loop or called repeatedly - Step 6: Test against edge cases (empty string, multiline, unicode, overlapping matches)
- Step 7: Apply flags (
re.IGNORECASE,re.MULTILINE,re.DOTALL,re.VERBOSE) as needed - Step 8: Verify no catastrophic backtracking on large/adversarial inputs
Recommendation▾
Include a brief section on performance considerations for very large inputs beyond backtracking
Core Function Reference
| Function | Purpose | Returns |
|---|---|---|
re.match(p, s) | Match at start of string only | Match object or None |
re.fullmatch(p, s) | Entire string must match | Match object or None |
re.search(p, s) | Find first match anywhere | Match object or None |
re.findall(p, s) | Find all non-overlapping matches | List of strings/tuples |
re.finditer(p, s) | Find all matches, lazily | Iterator of Match objects |
re.sub(p, repl, s) | Replace matches | New string |
re.subn(p, repl, s) | Replace + count | Tuple (string, count) |
re.split(p, s) | Split string by pattern | List of strings |
Examples18 / 20
Example 1: Extracting structured data with named groups Input:
Pythonlog = "2024-01-15 ERROR: Connection failed" pattern = re.compile(r'(?P<date>\d{4}-\d{2}-\d{2})\s+(?P<level>\w+):\s+(?P<msg>.+)') m = pattern.match(log)
Output:
Pythonm.group('date') # '2024-01-15' m.group('level') # 'ERROR' m.group('msg') # 'Connection failed' m.groupdict() # {'date': '2024-01-15', 'level': 'ERROR', 'msg': 'Connection failed'}
Example 2: Substitution with a function Input:
Pythontext = "price: 100, discount: 20" result = re.sub(r'\d+', lambda m: str(int(m.group()) * 2), text)
Output:
Python"price: 200, discount: 40"
Example 3: Splitting on multiple delimiters Input:
Pythonre.split(r'[,;]\s*', "apple, banana;cherry, date")
Output:
Python['apple', 'banana', 'cherry', 'date']
Example 4: Verbose mode for readable complex patterns Input:
Pythonpattern = re.compile(r""" (?P<area>\d{3}) # area code - (?P<num>\d{4}) # number """, re.VERBOSE) pattern.match("555-1234").groupdict()
Output:
Python{'area': '555', 'num': '1234'}
Recommendation▾
Consider trimming the Best Practices and Pitfalls lists slightly to tighten overall length, as some points overlap
Best Practices
- Always use raw strings (
r"...") for patterns to avoid double-escaping backslashes. - Use
re.compile()when the same pattern runs many times (loops, per-request validation). - Prefer non-capturing groups
(?:...)when you don't need to extract that group, for performance and clarity. - Use
\bword boundaries to avoid partial-word matches (e.g., matching "cat" inside "category"). - Use
re.VERBOSEwith inline comments for patterns longer than ~40 characters. - Anchor patterns (
^,$,\A,\Z) when the entire string must conform to a format — usefullmatch()instead ofmatch()when validating full strings. - For known-safe literal text, use
re.escape()before inserting user input into a pattern. - Use
finditer()instead offindall()when you need match positions (.start(),.end()) or when working with large text (lazy iteration).
Common Pitfalls
- Greedy quantifiers by default —
.*grabs as much as possible; use.*?for lazy/minimal matching when needed. - Forgetting
re.DOTALL—.does not match newlines by default; multiline text needsre.DOTALLif you want.to span lines. - Confusing
match()vssearch()—match()only anchors at the start of the string, not the whole string; unexpectedNoneresults often come from this. - Unescaped special characters — literal
.,*,+,(,),[,],{,},|,^,$,\must be escaped or passed throughre.escape(). - Catastrophic backtracking — nested quantifiers like
(a+)+on adversarial input can hang; prefer possessive-like restructuring or bound repetition counts. - Ignoring compiled flags scope — flags set inside
(?i)apply differently across Python versions/positions; prefer passing flags explicitly tore.compile(). - Using regex for deeply nested/structured data — HTML, JSON, or nested parentheses are not reliably parseable with regex; use a proper parser instead.