Quantifiers: how many times
A quantifier goes right after the thing it repeats.
| Quantifier | Meaning |
|---|---|
+ | one or more |
* | zero or more |
? | zero or one (optional) |
{3} | exactly 3 |
{2,4} | between 2 and 4 |
{2,} | 2 or more |
console.log(/^\d+$/.test("12345")); // → true
console.log(/^\d+$/.test("")); // → false (needs at least one)
console.log(/^\d*$/.test("")); // → true (zero or more)
console.log(/^colou?r$/.test("color")); // → true (u is optional)
console.log(/^\d{4}$/.test("2026")); // → true (exactly four digits)
console.log(/^\d{2,3}$/.test("1234")); // → false
Greedy vs lazy
Quantifiers are greedy: they match as much as they can. Add ? to make them lazy (as little as possible).
const html = "<b>bold</b> and <i>italic</i>";
console.log(html.match(/<.+>/)[0]); // → <b>bold</b> and <i>italic</i>
console.log(html.match(/<.+?>/)[0]); // → <b>
Groups: ( )
Parentheses group parts of a pattern so you can repeat them or capture them.
console.log(/^(ab)+$/.test("ababab")); // → true
const match = "2026-03-15".match(/^(\d{4})-(\d{2})-(\d{2})$/);
console.log(match[1], match[2], match[3]); // → 2026 03 15
match[0] is the whole match, and match[1], match[2]… are the captured groups in order.
Named groups
Give groups names with (?<name>...) so you do not have to count.
const { groups } = "2026-03-15".match(/^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/);
console.log(groups.year, groups.month, groups.day); // → 2026 03 15
Non-capturing groups
When you need grouping but not a capture, use (?:...).
console.log(/^(?:https?):\/\//.test("https://example.com")); // → true
Backreferences
\1 refers to the first captured group. It can find repeated text.
console.log(/\b(\w+) \1\b/.test("this is is a typo")); // → true