C.W.K.
Stream
Lesson 02 of 10 · published

Positive Lookahead — (?=...)

~8 min · lookahead, positive

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

Assert that something follows, without consuming it

(?=...) says "at the current position, the pattern inside the lookahead matches." The engine confirms but does not consume. Whatever's after the lookahead in the main pattern continues from the same position.

Three real uses

Constrain a match by what follows. \d+(?= dollars) matches a number ONLY IF "dollars" follows. Notice: 'dollars' is required for the match to succeed, but it's not part of the captured value.

Stack multiple requirements at the same position. (?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,} — "at the start, all three must be true: contains lowercase, contains uppercase, contains a digit, AND is 8+ chars." Each lookahead is a separate constraint, all anchored at the same position.

Find positions for splits without including the boundary. Useful with re.split when you want to split BEFORE a marker but keep it in the next chunk.

The cursor doesn't move

Critical mental model: after the lookahead succeeds, the engine is at the SAME position as before the lookahead. Anything written after the lookahead in the pattern starts matching from that position. So \d+(?=kg)kg would match the digits AND then re-match the 'kg' (because the cursor never moved past the lookahead's content).

Code

Positive lookahead patterns·python
import re

# Numbers followed by 'kg' — return just the number
re.findall(r'\d+(?=kg)', '5kg flour 2kg sugar 7lb butter')
# ['5', '2']

# Constraint: a word that ends with 'ing' (capture without 'ing')
re.findall(r'\w+(?=ing\b)', 'running jumping reading')
# ['runn', 'jump', 'read']

# Stacked lookaheads for password rules
password = re.compile(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$')
bool(password.match('Aa1aaaaa'))   # True
bool(password.match('aaaaaaaaa'))  # False (no upper, no digit)
bool(password.match('Aa1'))        # False (too short)

# Split before a capital letter without consuming it
re.split(r'(?=[A-Z])', 'CamelCaseString')
# ['', 'Camel', 'Case', 'String']

External links

Exercise

Write a regex matching numbers that are followed by 'MB' OR 'GB' (case sensitive). Return only the number. Test against the file is 12MB and the cache is 4GB and the limit is 100KB — only the first two should match.

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.