Goal
Understand how a regex engine actually executes a pattern.
Learn:
-
Consuming characters
-
Greedy matching
-
Backtracking
-
Lazy matching
-
How to mentally trace regex execution
Mental Model
A regex engine behaves like a tiny program.
Given:
catand:
dog cat birdThe engine tries:
position 0 -> fail
position 1 -> fail
position 2 -> fail
...
position 4 -> successThe engine scans through the text looking for a match.
Consuming Characters
When a pattern matches, it consumes characters.
Example:
abcText:
abcdefExecution:
a -> matches
b -> matches
c -> matchesConsumed:
abcGreedy Matching
Most quantifiers are greedy.
Greedy means:
Take as much as possible.Example:
a.*Text:
abcdefExecution:
a -> matches
.* -> consumes bcdefMatch:
abcdefGreedy Quantifiers
These are greedy by default:
*
+
{n,m}Examples:
.*
.+
\d+
[a-z]{3,10}All try to consume as much text as possible.
Backtracking
When a greedy match causes a later failure, the engine goes backwards.
Example:
a.*dText:
abcdefFirst attempt:
a -> a
.* -> bcdef
d -> failBacktrack:
.* -> bcde
d -> failBacktrack:
.* -> bcd
d -> matchesSuccess.
Match:
abcdVisual Model
Greedy matching:
Take everything
↓
Later part fails
↓
Give back characters
↓
Try againThis “give back” step is backtracking.
Common Interview Trace
Regex:
a.*bText:
axxbxxbxxExecution:
a -> matches
.* -> xxbxxbxx
b -> failBacktrack:
.* -> xxbxxbx
b -> failBacktrack:
.* -> xxbxxb
b -> failBacktrack:
.* -> xxbxx
b -> matchesResult:
axxbxxbWhy .* Causes Problems
Example:
<a>one</a><a>two</a>Regex:
<a>.*</a>Execution:
<a> matches first tag
.* consumes everything
</a> matches last closing tagResult:
<a>one</a><a>two</a>Often not what we intended.
Lazy Matching
Add a ’?’ after a quantifier.
Examples:
*?
+?
{n,m}?Meaning:
Take as little as possible.Example
Regex:
a.*?bText:
axxbxxbxxExecution:
a -> matches
.*? -> empty
b -> fail
.*? -> x
b -> fail
.*? -> xx
b -> matchesResult:
axxbGreedy vs Lazy
Greedy:
a.*bResult:
axxbxxbLazy:
a.*?bResult:
axxbImportant Distinction
Question mark has two meanings.
As a Quantifier
a?Means:
zero or one aAs a Lazy Modifier
a+?Means:
one or more a
but as few as possibleThe meaning depends on context.
Example
Regex:
a+?Text:
aaaaabExecution:
Take one a
If rest fails, expandResult:
aaaaaonly because the remaining pattern forces expansion.
Anchors Revisited
Regex:
abcMatches:
123abc456Regex:
^abc$Matches only:
abcbecause:
^requires start of string
and:
$requires end of string
Debugging Checklist
When a regex behaves unexpectedly, ask:
-
Where does matching begin?
-
Which part consumes characters?
-
Is a quantifier greedy?
-
Can the engine backtrack?
-
Would a lazy quantifier help?
Key Lessons
-
Regex engines consume text from left to right.
-
*,+,{n,m}are greedy by default. -
Greedy quantifiers take as much as possible.
-
Backtracking occurs when later matching fails.
-
Lazy quantifiers (
*?,+?,{n,m}?) take as little as possible. -
Most regex bugs involve unexpected greediness.
-
Think like the engine, not like the final result.
Mental Shortcut
Greedy:
Grab everything first.
Then backtrack.Lazy:
Grab nothing first.
Then expand.This simple model explains most regex behavior.