Pulling pieces out with groups
Parentheses in a pattern create groups, letting you capture the interesting parts of a match separately:
import re m = re.search(r"(\w+)@(\w+)\.com", "mail ada@example.com now") m.group(0) # 'ada@example.com' the whole match m.group(1) # 'ada' m.group(2) # 'example'
Two more workhorses:
re.findall(pattern, text)returns every match as a list of strings, or a list of tuples when the pattern has groups.re.sub(pattern, replacement, text)replaces every match. In the replacement,\1refers back to group 1.
Groups are where regex pays its rent: they turn a yes/no matcher into an extraction tool that pulls every (name, score), (date, amount), or (level, message) pair out of a pile of text in two lines.
Code exercise · python
Run this program. findall grabs every price, sub censors the card number but keeps the last four digits with a group backreference.
Lookahead: check without consuming
A lookahead (?=...) peeks forward without including that text in the match. The classic use is password rules, several conditions on the same stretch of text:
r"^(?=.*\d)(?=.*[A-Z]).{8,}$"Read it as: at the start, peek: somewhere ahead there is a digit. Peek again: somewhere ahead there is an uppercase letter. Then actually match 8 or more characters to the end. Each lookahead rewinds to the start after checking, which is how all the rules can apply at once.
Keep regex honest: it shines for flat token patterns like codes, prices, and log lines. The moment you are parsing nested structure, where values contain values that contain values, like the JSON data format coming in unit 8 or the HTML markup of a web page, switch to a real parser built for that format (unit 8 covers json).
Code exercise · python
Your turn. Use findall with two groups to extract each (name, score) pair from the log, then print each name with its score converted to int plus 10 bonus points.
Code exercise · python
Your turn. Privacy pass: replace every email address in the text with [hidden] using ONE re.sub call. A good-enough email pattern here is: word characters, @, word characters, a literal dot, word characters.
Quiz
re.findall(r"(\d+)-(\d+)", "7-2 and 10-4") returns what?
Problem
In the pattern r"colou?r", which single character is optional? Answer with just that character.