regexhelper
Test a pattern. Copy a ready-made one. No signup.

Greedy vs Lazy Quantifiers

Quantifiers control how many times something repeats. The catch: by default they are greedy and grab as much as possible. Here is when that bites and how lazy and possessive versions fix it.

The quantifiers

GreedyLazyPossessiveRepeats
**?*+0 or more
++?++1 or more
????+0 or 1
{2,5}{2,5}?{2,5}+2 to 5

The greedy trap

Given the string <b>one</b> <b>two</b> and the pattern:

<b>.*</b>

A greedy .* matches the entire string in one go — from the first <b> to the last </b> — because it grabs everything, then backtracks just enough to let </b> match.

The lazy fix

<b>.*?</b>

The lazy .*? matches as little as possible, so you get two separate matches: <b>one</b> and <b>two</b>.

Often better than lazy: a negated class

<b>[^<]*</b>

Instead of "match anything, lazily", say "match anything that is not a <". This avoids backtracking entirely and is usually faster and more predictable.

Possessive quantifiers and catastrophic backtracking

A pattern like (a+)+$ against a long string of as followed by a ! can explode into millions of backtracking steps — a real denial-of-service risk (ReDoS). Possessive quantifiers (a++) and atomic groups (?>...) refuse to give back characters, killing that blow-up. They are supported in PCRE, Java and .NET, but not in stock JavaScript.

Rule of thumb

  • Reach for a negated class first ([^"]*, [^<]*).
  • Use lazy when there is no clean delimiter to negate.
  • Use possessive/atomic when a pattern risks catastrophic backtracking.

FAQ

What does the ? after * or + mean?

It makes the quantifier lazy (non-greedy): the engine matches as few characters as possible while still allowing the overall pattern to succeed. So .*? stops at the first opportunity instead of the last.

Is lazy matching slower than greedy?

Not inherently — it just backtracks in the opposite direction. For structured text a negated character class like [^<]* is usually faster than either, because it never has to backtrack.

What is catastrophic backtracking?

When nested quantifiers create exponentially many ways to match, a small input can hang the engine. Avoid patterns like (a+)+ and use atomic groups or possessive quantifiers to prevent it.