Quantifiers
Control how many times an element must appear — from optional to unlimited — and understand the greedy vs lazy distinction.
- Apply *, +, ?, {n}, {n,}, and {n,m} correctly
- Predict whether a greedy quantifier will match more or fewer characters
- Convert a greedy quantifier to lazy with ?
A quantifier tells the engine how many times the preceding atom — a single character, a shorthand class, or a group — must appear. Without quantifiers you can only match fixed-length text. With them you can match "one or more digits," "zero or one space," or "exactly three uppercase letters."
The six quantifiers
| Quantifier | Meaning | Example | Matches |
|---|---|---|---|
* | 0 or more | /\d*/ | "", "5", "42", "1000" |
+ | 1 or more | /\d+/ | "5", "42", "1000" |
? | 0 or 1 | /colou?r/ | "color", "colour" |
{n} | Exactly n | /\d{4}/ | "2024" |
{n,} | n or more | /\d{2,}/ | "12", "345", "1000" |
{n,m} | Between n and m | /\d{2,4}/ | "12", "123", "1234" |
* — zero or more
* matches the preceding atom any number of times, including zero. It is useful
when something might or might not be present:
/go*d/.test("gd"); // true — zero 'o's
/go*d/.test("god"); // true — one 'o'
/go*d/.test("good"); // true — two 'o's+ — one or more
+ requires at least one match. It is the most common quantifier because "at
least one" captures the usual meaning of "a number," "a word," etc.:
/\d+/.test("abc"); // false — no digits at all
/\d+/.test("abc1"); // true — found '1'
/\d+/.test("abc123"); // true — found '123'? — optional
? makes the preceding atom optional (zero or one occurrence):
/https?:\/\//.test("http://example.com"); // true — no 's'
/https?:\/\//.test("https://example.com"); // true — with 's'The pattern /colou?r/ matches both British and American spelling because u is
optional.
{n} — exact count
/\b\d{4}\b/.test("year 2024"); // true — exactly four digits
/\b\d{4}\b/.test("year 24"); // false — only two digits\b in the examples above is a word boundary anchor (covered in the next
lesson). Here it just prevents /\d{4}/ from matching the first four digits of
a longer number like 12345.
{n,} — at least n
/\w{5,}/.test("hi"); // false — only 2 characters
/\w{5,}/.test("hello"); // true — exactly 5
/\w{5,}/.test("excellent"); // true — 9 characters{n,m} — bounded range
/\d{2,4}/.test("1"); // false — only 1 digit
/\d{2,4}/.test("12"); // true — 2 digits
/\d{2,4}/.test("12345"); // true — matches first 4Note the last example: the engine matches as many as the upper bound allows inside the string; it does not require the whole string to be that length.
Greedy vs lazy
By default, quantifiers are greedy — they consume as many characters as possible while still allowing the overall pattern to match:
const html = "<b>hello</b> and <b>world</b>";
const m = html.match(/<.+>/);
console.log(m[0]); // "<b>hello</b> and <b>world</b>"The + expanded as far as possible, swallowing both tags and everything between
them. That is usually not what you want when matching HTML-like content.
Adding ? after a quantifier makes it lazy — it matches as few characters as
possible:
const html = "<b>hello</b> and <b>world</b>";
const m = html.match(/<.+?>/);
console.log(m[0]); // "<b>"Now +? stops at the first > it finds.
| Greedy | Lazy | Behaviour |
|---|---|---|
* | *? | As few as possible (0 preferred) |
+ | +? | As few as possible (1 minimum) |
? | ?? | As few as possible (0 preferred) |
{n,m} | {n,m}? | As few as possible within range |
Lazy quantifiers are not always faster. In some patterns they cause the engine to
backtrack extensively. If you find yourself depending on greedy-vs-lazy to fix a
pattern, often a more precise character class is the cleaner solution: [^>]+
instead of .+? when matching content that should stop at >.
Common mistakes
Forgetting that * allows zero matches. /\d*\.csv/ matches ".csv" because
\d* can match zero digits. Use \d+ if at least one digit is required.
Applying a quantifier to the wrong atom. In /ab+/, the + applies only to
b, not to ab. To repeat the pair, use a group: /(ab)+/.
Where to go next
Next: anchors — ^, $, and \b nail a pattern to a specific position in
the string rather than letting it float anywhere.