Quantifiers say how many times the thing before them may repeat. They turn "one digit" into "five digits," "one or more letters," or "an optional s." Every quantifier applies only to the single item right before it: one character, one class, or one group.
| Quantifier | Means | Example |
|---|---|---|
| * | 0 or more | /go*gle/ : ggle, gogle, google |
| + | 1 or more | /\d+/ : 7, 42, 2026 |
| ? | 0 or 1 (optional) | /colou?r/ : color, colour |
| {n} | Exactly n | /\d{5}/ : 21201 |
| {n,} | n or more | /.{8,}/ : 8+ characters |
| {n,m} | Between n and m | /\d{2,4}/ : 2 to 4 digits |
"a aa aaa aaaa".match(/\ba{2,3}\b/g) // ["aa", "aaa"]
"file1 file22 file333".match(/file\d+/g) // ["file1", "file22", "file333"]
/^https?:\/\//.test("http://x.org") // true (the s is optional)
With the g flag you can see exactly what each quantifier grabs:
const text = "Hellooo World! Hello W3Schools!";
console.log(text.match(/o+/g)); // one or more o's
console.log(text.match(/lo*/g)); // an l, then zero or more o's
console.log("1, 100 or 1000?".match(/10?/g)); // a 1, then an optional 0
const nums = "100, 1000 or 10000?";
console.log(nums.match(/\d{4}/g)); // exactly 4 digits
console.log(nums.match(/\d{3,4}/g)); // 3 to 4 digits
console.log(nums.match(/\d{3,}/g)); // 3 or more digits
\d{4} found "1000" twice. The second one is the first four digits of "10000". A quantifier counts characters; it does not know where a number ends. Add word boundaries to match whole numbers only: "100, 1000 or 10000?".match(/\b\d{4}\b/g) is ["1000"].
/ha+/ // "h" then one or more "a": ha, haa, haaa
/(ha)+/ // "ha" repeated: ha, haha, hahaha
/[ha]+/ // any mix of h and a: h, aah, hahh
/ha+/ does not repeat "ha". The + only sees the a. To repeat more than one character, wrap them in a group first.
Quantifiers grab as much as possible while still letting the overall pattern match. This is called being greedy, and it causes a classic surprise:
const html = "<b>bold</b> and <i>italic</i>";
html.match(/<.+>/)[0];
You wanted just <b>, but .+ ran all the way to the last > in the text.
Put ? after any quantifier to make it lazy: it takes as little as possible.
html.match(/<.+?>/g);
| *? +? ?? | Lazy versions of * + ? |
| {n,m}? | Lazy range: as few as n |
/<[^>]+>/g says "a <, then any characters that are not >, then >." It cannot overshoot, and it is easier to read than a lazy quantifier.
"Zero or more" includes zero. A pattern made only of x* succeeds everywhere, by matching empty text:
console.log("abc".match(/x*/g));
Four empty matches: one before each letter and one at the end. When you need at least one, use +.
You might guess /a{,3}/ means "up to 3 a's." It does not. Without the u flag, a { that does not form a valid quantifier is treated as plain text:
console.log(/a{,3}/.test("aaa")); // not a quantifier...
console.log(/a{,3}/.test("a{,3}")); // ...it matches this exact text
Write {0,3} instead. With the u flag, the mistake becomes a clear error: new RegExp("a{,3}", "u") is SyntaxError: Invalid regular expression: /a{,3}/u: Incomplete quantifier.
Quantifiers shorten patterns you have already seen:
/^[A-Z][A-Z][A-Z]-\d\d\d\d$/ // before
/^[A-Z]{3}-\d{4}$/ // after: same meaning
/^\d{3}-\d{3}-\d{4}$/ // US phone: 410-555-0199
/^\s+|\s+$/g // whitespace at either end (what trim() removes)
What does this log?
console.log("zzz zz z".match(/z{2}/g));
["zz", "zz"]. The first match is the first two letters of "zzz". The leftover "z" is only one letter, so it does not match. Then "zz" matches, and the last "z" is too short.Which matches "color" and "colour" but not "colouur"?
/colou*r//colou+r//colou?r//colo.*r/? allows zero or one u. A and D also accept "colouur", and B rejects "color".Rewrite /^\d\d\d\d\d$/ using a quantifier.
/^\d{5}$/. {5} means exactly five of the item before it.