Course outline · 0% complete

0/27 lessons0%

Course overview →

Groups, findall, sub, and a lookahead

lesson 7-2 · ~13 min · 19/27

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, \1 refers 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.