In a regular expression, what is the difference between a greedy quantifier and a lazy one?
answer
- same language, different preferred match
- how much does the repeat take first?
- greedy takes all, then gives back
- lazy starts empty, grows by one
- a negated class avoids the question
basics
~20 sA greedy quantifier takes as many repetitions as it can and gives characters back only when the rest of the pattern fails; a lazy one takes as few as possible and grows one at a time.
solid answer
~40 sBoth forms accept exactly the same strings; they differ in which match is preferred, and therefore in what you read out afterwards. `.*` first consumes as far as it can, then releases one character at a time until the remainder of the pattern can succeed, so it settles on the longest run that still works. `.*?` starts at zero repetitions and extends one at a time, so it settles on the shortest run that works. On the line `user=alice;action=login;` the pattern `=(.*);` captures `alice;action=login`, because the greedy run gives back only as far as the *last* `;`. Written lazily, `=(.*?);` captures `alice`. The preference is local to that quantifier — it is not a promise about the length of the overall match.
go deeper
Remember the direction of each: greedy grabs the most it can and backs off, lazy grabs the least and grows. Be able to say which one stops at the first delimiter in a key=value line.
Explain that both forms accept the same language and only the preference order differs, and show the backtracking sequence that leaves the longest run in the capture group.
Show the habit of reading every unrestricted run in a pattern and asking what it can swallow on a malformed line, then replacing it with a negated class so the boundary is stated rather than inferred.
Frame it as a contract question: patterns that rely on a preference order to stop in the right place are fragile when input shape drifts, so a house style that requires explicit delimiters pays for itself across a fleet of extractors.
## The two forms describe the same language A **quantifier** says how many times the element before it may repeat: `*` is zero or more, `+` is one or more, `{2,5}` is a bounded repeat. Writing `?` after a quantifier makes it **lazy** (also called reluctant or non-greedy): `*?`, `+?`, `{2,5}?`. The first thing to pin down is what does *not* change. A greedy pattern and its lazy twin accept exactly the same set of strings — as formal languages they are identical, and a machine built from either recognises the same inputs. What changes is which of the many valid matches is **preferred**, and therefore what ends up in the capture groups. That matters because a pattern applied to real input almost always has several valid matches and you only ever see one of them. ## Greedy: take everything, then give it back A greedy quantifier is not a promise to swallow the rest of the input; it is an **order of attempts**. Applying `=(.*);` to `user=alice;action=login;`: 1. The match begins at the leftmost position where any match can start — here the first `=`, at offset 4. 2. `.*` takes everything to the end of the line. 3. The pattern still needs a `;`, and there is nothing left, so `.*` gives one character back. 4. It keeps giving characters back until a `;` sits at the current position — which happens at the **final** `;`. 5. The whole match is `=alice;action=login;` and group 1 holds `alice;action=login`. The field extractor was meant to pull one field and it swallowed two. Nothing malfunctioned: the pattern asked for the longest run of any character that still leaves a `;` behind, and that is what it got. ## Lazy: take nothing, then grow A lazy quantifier reverses the order. `=(.*?);` starts `.*?` at zero characters, checks whether a `;` follows, and only if that fails does it take one more character. On the same line it stops the moment the first `;` appears, so group 1 holds `alice`. Again nothing about the *possible* matches changed — only which one is tried first. ## The same line, three patterns | pattern | whole match on `user=alice;action=login;` | group 1 | |---|---|---| | `=(.*);` | `=alice;action=login;` | `alice;action=login` | | `=(.*?);` | `=alice;` | `alice` | | `=([^;]*);` | `=alice;` | `alice` | The third row is the one experienced authors reach for. A **negated character class** — "any character that is not a delimiter" — states the intent directly instead of relying on a preference order to stop in the right place, and it reads the same to every engine. ## Choosing between them - Use **lazy** when the closing delimiter is the *first* one after the field: quoted values, tag-like wrappers, a key up to the first separator. - Use **greedy** when you genuinely want the widest span: everything up to the last separator, a trailing remainder, the final extension in a name. - Prefer a **negated class** whenever the boundary is a single known character; it removes the question entirely. - Do not assume lazy is cheaper. If the text you are looking for sits far to the right, a lazy quantifier extends one character at a time all the way there, while a greedy one may land near it immediately. Which is cheaper depends on the input, not on the marker. ## What neither form changes - **The set of strings the pattern accepts.** Only the preferred match changes. - **Where the match starts.** The starting position is chosen first — the leftmost position at which any match exists — and the quantifier's preference only decides among the matches available there. - **The meaning of the surrounding pattern.** Anchors, classes and group numbering behave identically either way. - **Whether the overall match is the longest one possible.** Greedy expresses a preference at one quantifier; an earlier part of the pattern can still settle on a shorter overall span. The practical habit is to read every `.*` in a pattern and ask "what is it allowed to swallow on a bad line?". A field extractor that looks correct on one well-formed sample and returns too much on the next one almost always has a greedy run crossing a delimiter it was never meant to cross.
- Does making a quantifier lazy change which strings the pattern can match at all?No. The two forms accept the same language; an input either has a match or it does not, regardless of the marker. What changes is which of the valid matches is reported, and therefore the spans and captures you read out afterwards.
- How would you rewrite `=(.*?);` without using a lazy quantifier?Use a negated character class: `=([^;]*);`. It says directly that the field contains no delimiter, so there is only one match to find rather than a preference order that happens to stop in the right place, and it reads identically under every match-semantics convention.
Greedy is a shopper who fills the bag to the top and then puts items back until it closes; lazy is one who puts in a single item and adds another only when told it is not enough.
saying these in an interview costs you the question
- Says greedy and lazy versions accept different sets of strings
- Thinks a lazy quantifier is always faster than a greedy one
- Believes a lazy quantifier can never span a long piece of text
- Treats greedy as a guarantee of the longest overall match
- Puts an unrestricted run between two delimiters and blames the engine