snaptxt.app
Blog
Data Tools4 min readJuly 15, 2026

Greedy vs. Lazy Regex Matching: Why Your Pattern Matches Too Much

<.+> looks like it should match one HTML tag. Run it against <b>bold</b> and it matches the entire string, tags and all, instead of stopping at the first >. That's not a bug in the regex engine — it's greedy matching doing exactly what it's designed to do, and it's the single most common reason a pattern that "obviously" should work doesn't.

Greedy quantifiers grab as much as possible, then backtrack

By default, *, +, and {n,} are greedy: they try to match as many characters as possible first, and only give characters back if the rest of the pattern fails to match otherwise. <.+> against <b>bold</b> greedily consumes everything up to the last > in the string, because .+ will happily eat through </b> and bold too — it only backs off if forced to.

This is invisible on short test strings where there's only one > to find, and only becomes obvious once real data has more than one instance of the closing character.

Lazy quantifiers stop at the first match that works

Adding a ? after a quantifier makes it lazy instead: <.+?> tries to match as few characters as possible, expanding only when the rest of the pattern demands it. Against the same string, <.+?> stops at the very first > it can — matching just <b>, not the whole tag soup.

The rule of thumb: if a pattern is matching more than you expect, especially across multiple similar delimiters, the fix is almost always adding ? after the greedy quantifier that's overreaching.

When greedy is actually what you want

Greedy isn't wrong by default — it's wrong when there's more than one instance of your closing character in the string. It's the right choice when:

  • You're matching to the last occurrence of something on purpose (trimming trailing whitespace with \s+$, for example).
  • There's genuinely only one possible closing delimiter in valid input.
  • Performance matters and you've confirmed backtracking isn't a problem — lazy quantifiers can be slower on some inputs because they check more incrementally.

A quick test to catch the bug before it ships

Run the pattern against a string with two instances of your delimiter, not one. <b>bold</b> and <i>italic</i> will immediately expose a greedy <.+> matching from the first < to the last >, spanning both tags — the exact failure mode that a single-tag test string hides.

Try it

The Regex Tester highlights every match live as you type, so a greedy pattern eating more than intended is visible immediately instead of surfacing later against production data.

guideregex
H

Hanuman Singh · built snaptxt.app · hanumansingh.dev