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

Why 'Zero-Width' Matters

~6 min · zero-width, engine

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

The cursor stays where it is

The single most important property of lookaround: after the assertion runs, the engine is at the same position as before. No characters have been consumed.

This has two practical consequences:

1. Multiple lookarounds at one position chain naturally. Each one peeks from the same spot. (?=A)(?=B)(?=C) means "A AND B AND C all match starting from here."

2. The text inside the lookaround can OVERLAP with subsequent matches. (?=cat)\w+ first asserts 'cat' starts here, then matches \w+ which actually consumes 'cat' (and possibly more). Same characters, two roles.

Compare to consuming alternatives

Pattern cat\d+ consumes 'cat' and then matches digits. After this, the cursor is past the digits.

Pattern (?=cat)\d+ would never match — it asserts 'cat' here, then tries to match digits AT THE SAME POSITION, but the position is 'c', not a digit.

Pattern (?=cat\d)cat\d+ works — assert 'cat' then a digit follows, then actually match cat and the digits.

Why this matters for splits

Zero-width matching is what lets re.split(r'(?=[A-Z])', 'CamelCase') split at every uppercase letter without DELETING the uppercase letter. The split position is detected without consuming the boundary character.

Code

Zero-width in action·python
import re

# Lookahead doesn't consume — multiple at same position chain
re.findall(r'(?=\d)(?=\d{2})\d+', '5 12 345')
# ['12', '345']  — must be a digit AND have at least 2 digits

# Without lookahead, you'd consume the first digit
re.findall(r'\d{2}\d+', '5 12 345')
# ['345']  — different result; consumes 2 digits then continues

# Split keeping the delimiter
re.split(r'(?=[A-Z])', 'CamelCaseString')
# ['', 'Camel', 'Case', 'String']

# Splitting WITH delimiter consumed (no lookahead)
re.split(r'[A-Z]', 'CamelCaseString')
# ['', 'amel', 'ase', 'tring']  — capitals deleted

External links

Exercise

Use re.split with a lookahead to split a snake_case string hello_world_pippa so that the underscore stays attached to the next word: ['hello', '_world', '_pippa']. Hint: the lookahead asserts an underscore is next.

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.