*?, +?, ??, {n,m}? — as little as possible, one more at a time¶
One line: A ? after any quantifier makes it lazy: it matches the minimum first and extends one repetition at a time only when the rest of the pattern fails; all eight engines here agree on every row, and the engine that does not — POSIX, where a+? is (a+)? — is not one the driver can ask.
Level: reference · one construct, eight engines
What it means¶
| Greedy | Lazy | Tries first |
|---|---|---|
x* |
x*? |
zero, then one, then two… |
x+ |
x+? |
one, then two… |
x? |
x?? |
zero, then one |
x{n,m} |
x{n,m}? |
n, then n+1… |
Lazy is not "the fast one" and not "the correct one". It is the one that finds a different match when both a short and a long match are possible from the same start — and when only one match is possible, it finds the same match by a different route.
Measured¶
Verified output of kw_lazy_quantifier_sh.sh — regenerated by tools/run_examples.py, never hand-typed.
construct python perl node ruby java go rust fancy
greedy <b>x</b> <b>x</b> <b>x</b> <b>x</b> <b>x</b> <b>x</b> <b>x</b> <b>x</b>
lazy <b> <b> <b> <b> <b> <b> <b> <b>
?? prefers nothing "" "" "" "" "" "" "" ""
{2,3}? stops at two aa aa aa aa aa aa aa aa
lazy at the end name= name= name= name= name= name= name= name=
lazy, anchored name=x name=x name=x name=x name=x name=x name=x name=x
Reading the table¶
- Rows 1–2.
<.+>takes the whole of<b>x</b>;<.+?>takes<b>. Eight engines, one answer each — this is the canonical demonstration and there is nothing to disagree about. - Row 3,
a??ona. All eight match the empty string. The lazy optional prefers nothing, and nothing is enough for the pattern to succeed, so theais never consumed. - Row 4,
a{2,3}?. Two, the minimum, in every engine. - Rows 5–6.
name=.*?matchesname=— a lazy quantifier at the very end of a pattern has nothing after it to force extension, so it always takes zero. Add$and it takes everything up to the end, exactly as.*would have. A trailing.*?is a no-op in every engine here; a trailing.*?$is spelled.*$.
The trap¶
Two. The first is performance folklore: .*? is not cheaper than .*, and on a subject where the match ends late it is more expensive, because it extends one character at a time and retries the tail at every step. The lesson measures the read counts in Java both ways.
The second is portability. POSIX engines — grep, sed, awk, C's <regex.h> — have no lazy quantifier, and a+? parses there as (a+)?, a legal pattern with a different meaning. A pattern using .*? moves from Python to sed and keeps working, wrongly. That engine is not in the table above because the probe cannot drive it; the lesson has the C program and the dated grep/sed runs.
Where it is measured in depth¶
See also¶
*,+,?·{n,m}— the greedy forms.- Possessive
*+— the third mode. - Extracting fields — where lazy earns its keep.