Non-Greedy Quantifiers — *?, +?, and ?? Explained

Master non-greedy (lazy) quantifiers *?, +?, ?? in regex. Learn when to use them, how they differ from greedy quantifiers, and the negated-class alternative.

Advanced Techniques

Detailed Explanation

Non-Greedy (Lazy) Quantifiers

By default, quantifiers in regex are greedy: they consume as much as possible and only give back when forced. Non-greedy quantifiers do the opposite: they consume as little as possible while still allowing the overall match to succeed.

The Three Lazy Quantifiers

Greedy Lazy Meaning
* *? Zero or more, prefer fewer
+ +? One or more, prefer fewer
? ?? Zero or one, prefer zero

Greedy vs Lazy in Action

Input: <b>bold</b><i>italic</i>

Greedy: <.+>   matches "<b>bold</b><i>italic</i>"  (whole string)
Lazy:   <.+?>  matches "<b>"                        (first tag only)

The greedy version overshoots because .+ consumes everything until the last >.

Tested Examples

Pattern Input Match
a.*b (greedy) "axbyb" axbyb
a.*?b (lazy) "axbyb" axb
<.+> "<a><b>" <a><b>
<.+?> "<a><b>" <a>
".+?" '"a","b"' "a"

The Negated-Class Alternative

Lazy quantifiers can backtrack badly on long inputs. Often a negated character class is faster and clearer:

Lazy:    "(.+?)"
Better:  "([^"]+)"

The negated version reads "match characters that are not a quote" and is much faster because it never backtracks.

When Lazy Wins

When the closing delimiter can also appear inside, you cannot use a simple negated class. For example, matching nested tags or escaped quotes requires either a lazy quantifier or an unrolled-loop pattern ([^"\\]|\\.).

Possessive Quantifiers (Not in JavaScript)

Some engines (PCRE, Java) support possessive quantifiers (*+, ++) that never give back. JavaScript does not, but you can simulate them with atomic-group emulation: (?=(pattern))\1.

Practical Recommendations

  1. Default to greedy + negated class when possible ([^>]+ over .+?)
  2. Use lazy when delimiters can nest or repeat
  3. Test pathological inputs to catch performance issues early

Use Case

Extracting the first occurrence of a delimited substring (HTML tag, quoted text, JSON value), parsing log lines where you want the smallest match between fixed boundaries, or matching balanced delimiters where greedy patterns overshoot.

Try It — Regex Cheat Sheet

Open full tool