C.W.K.
Stream
Lesson 06 of 12 · published

Greedy Matching — The Default Behavior

~10 min · greedy, engine

Level 0Pattern-Curious
0 XP0/90 lessons0/15 achievements
0/100 XP to next level100 XP to go0% complete

Quantifiers grab as much as possible by default

By default, all quantifiers are greedy. They consume as many characters as they can, then backtrack only if the rest of the pattern fails to match.

The classic example: pattern a.*b against input a123b456b. Naive expectation: it matches a123b (the first b after a). Reality: it matches a123b456b (everything from the first a to the LAST b).

Why greedy by default

Backtracking. The engine tries to match .* against the entire rest of the string, sees that b doesn't follow (because we're at end of string), then backtracks one character and tries again. It keeps backtracking until it finds a position where the literal b matches — which happens at the LAST b, not the first.

Once you internalize "greedy means longest possible," half of regex's surprises stop being surprises.

The greedy trap

The most common mistake in beginner regex: trying to extract a substring between two markers using .* (which is greedy). It will eat past your intended endpoint to the LAST occurrence of the closing marker.

Code

Greedy in slow motion·python
import re

# Greedy: matches the LONGEST possible substring
re.findall(r'a.*b', 'a123b456b')
# ['a123b456b']  — NOT just 'a123b'

# Same with HTML — disaster
html = '<p>first</p> <p>second</p>'
re.findall(r'<p>.*</p>', html)
# ['<p>first</p> <p>second</p>']  — eats both paragraphs as one match

# Greedy + backtracking visualization
# Pattern: a\d+b against 'a12345b6789b'
# 1. \d+ grabs '12345b6789'  → next char must be 'b', position is past end
# 2. Backtrack one char: \d+ becomes '12345b678'  → still no 'b' next, but wait
# 3. Actually \d+ can't grab 'b' (not a digit), so it grabs only '12345'
# 4. Then 'b' matches at position 6
re.findall(r'a\d+b', 'a12345b6789b')
# ['a12345b']  — \d+ couldn't include b in the first place

External links

Exercise

Predict what re.findall(r'".*"', '"a" "b" "c"') returns. Run it. The result should explain why beginners hate .* for parsing quoted strings.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.