Three behaviors, same symbols
Quantifiers (*, +, ?, {n,m}) control repetition, but three distinct matching strategies exist for how they consume input:
| Style | Syntax | Behavior |
|---|---|---|
| Greedy (default) | a*, a+ |
Match as much as possible, backtrack if the rest of the pattern fails |
| Lazy | a*?, a+? |
Match as little as possible, expand only if needed |
| Possessive | a*+, a++ |
Match as much as possible, never backtrack |
Greedy vs. lazy on the same input
Input: <b>bold</b>
Pattern: <.+>
Greedy: <b>bold</b> (spans from the first < to the LAST >)
Lazy: <.+?> → <b> (stops at the FIRST >, matching the smallest valid span)
Greedy quantifiers try to consume the whole rest of the string first, then backtrack character by character until the remaining pattern can match — which is exactly why greedy .+ between repeated delimiters tends to span far more than intended. Lazy quantifiers do the opposite: start with the minimum possible match and only grow if the pattern requires more.
Possessive: greedy, but refuses to backtrack
Possessive quantifiers behave like greedy ones on the first attempt — consuming as much as possible — but if the rest of the pattern subsequently fails, a possessive quantifier won't give back characters to try an alternative; the whole match attempt fails outright instead. This sounds like a strict downgrade, but it's actually a deliberate performance tool: for patterns that would otherwise backtrack extensively on non-matching input, possessive quantifiers can fail fast instead, avoiding the same exponential-style backtracking that causes ReDoS (catastrophic backtracking) in vulnerable patterns.
Pattern: a*+a (possessive a*, followed by literal 'a')
Input: "aaa"
Result: NO MATCH — a*+ greedily consumes all three a's, then refuses to give any back
for the trailing literal 'a' to match, even though "aa" + "a" would work
Note: possessive quantifiers aren't supported in every regex flavor (JavaScript's native engine, for instance, historically lacked them — check your specific environment before relying on the syntax).
When to reach for each
- Greedy (default): fine for most patterns where the input's shape prevents ambiguity — e.g., matching digits with
\d+where there's nothing else nearby to over-consume. - Lazy: reach for this whenever a repeated delimiter is involved (quotes, tags, brackets) and you want the smallest valid match, not the largest.
- Possessive: a targeted performance/safety tool for patterns where backtracking would be wasted work or a real ReDoS risk — not a general-purpose default.
Common mistakes
- Defaulting to greedy without checking for repeated delimiters in the input. This is the single most common cause of "my regex matched way more text than expected."
- Assuming lazy quantifiers are always "correct." Sometimes greedy is exactly right — e.g., matching the longest possible number, where you genuinely want maximum consumption.
- Reaching for possessive quantifiers as a default speed optimization. They change matching semantics (no backtracking, which can cause valid matches to be missed) — use them deliberately, not automatically.
FAQ
What's the practical difference between greedy and lazy quantifiers?
Greedy consumes as much as possible before backtracking if needed; lazy consumes as little as possible and only grows the match if the rest of the pattern requires it — this matters most with repeated delimiters.
Do possessive quantifiers ever backtrack?
No — that's their defining trait; once they've consumed input, they won't give any back, even if that means the overall match fails when a greedy quantifier would have succeeded.
Are possessive quantifiers supported everywhere?
No — support varies by regex engine/language; check your specific environment before relying on the syntax.
Test greedy, lazy, and other quantifier behaviors live against real input with the Regex Tester — entirely client-side.