What's the Difference Between Greedy and Lazy Matching in Regex
What's the difference between greedy and lazy matching, and when does it actually matter? Greedy quantifiers match as much as they can while still letting the rest of the pattern succeed; lazy quantifiers match as little as possible first. The choice changes which text your regex captures — sometimes silently.
What does greedy matching actually do?
A greedy quantifier (*, +, ?, {n,m}) tries to consume as much input as possible, then backtracks only as far as needed for the rest of the pattern to match. For example, a.+b against aXbYb matches the whole aXbYb, because .+ stretches to the last b. Lazy is not the default — you have to ask for it explicitly.
What does lazy matching actually do?
A lazy quantifier (*?, +?, ??, {n,m}?) starts by matching as little as possible and expands only when the rest of the pattern forces it. The same a.+?b against aXbYb matches just aXb — it stops at the first b. Same pattern, different answer, purely because of the ?.
When does the difference actually matter?
It matters whenever the same pattern can match in more than one place. Classic cases: extracting text between HTML tags (<.+?> stops at the first closing bracket, <.+> runs to the last one), parsing quoted strings, or splitting log lines where a field value may contain the delimiter. If your regex has only one possible match, greedy vs lazy changes nothing — but you usually can't know that without testing.
Does greedy always match more than lazy?
Not exactly. Greedy matches as much as it can, but the overall pattern still has to succeed — it backtracks when needed. Lazy matches as little as possible, but expands when the rest of the pattern needs more. They often produce different matches, but in a pattern with a single unambiguous match, both end at the same place. The real risk is a greedy capture that swallows content you wanted kept separate.
Why does greedy matching sometimes break my capture groups?

Because a greedy quantifier expands into text that belongs to a later part of the pattern. Take extracting the middle of a URL: https://(.+)/page against https://site.com/a/b/page captures site.com/a/b in the group, not just site.com. Switch to (.+?) and you get site.com. The greedy version isn't wrong — it's just grabbing the last occurrence instead of the first.
How do I decide which one to use?
Ask what you're delimiting. If the text you want ends at the first occurrence of a marker (first >, first ", first comma that isn't escaped), use lazy. If it should extend to the last occurrence (the final > of a whole block, the last / of a path), use greedy. When in doubt, test both against your real data — a regex that works on your sample but captures too much in production is a bug you'll chase for a day.
Are lazy quantifiers slower than greedy ones?
Sometimes. Lazy matching does more incremental steps — it keeps re-checking the next part of the pattern after every character it adds. On short strings you won't feel it; on long inputs or patterns with lots of optional parts, lazy can be noticeably slower. Greedy can also blow up with catastrophic backtracking on pathological patterns. The practical rule: pick by correctness first, optimize only if profiling shows a problem.
What's the most common greedy-vs-lazy bug people hit?
Extracting between two identical delimiters. Parsing --name "John" --city "New York" with "(.+)" grabs everything between the first and last quote — John" --city "New York — when you wanted just John. Switching to "(.+?)" fixes it. This is the single most frequent capture-group surprise, and it's why lazy is worth knowing even if you rarely reach for it.
How can I test this without guessing?
Run both variants on a small set of realistic inputs and print the full matches and capture groups. Most regex testers show you the exact match span, so the difference is visible in one screen. Keep a few edge cases — empty matches, adjacent delimiters, content containing the delimiter — because those are where greedy and lazy visibly part ways.