{n}: matching exactly n repetitions
{n} matches exactly n repetitions of the preceding token. Applied to a capture group it repeats the match n times but keeps only the text of the last iteration.
At a glance
- Syntax
- {n}
- Meaning
- exactly n repetitions of the preceding token
- On a group
- the capture keeps only the final iteration
- Without anchors
- it still matches inside a longer run, so /\d{4}/ matches part of 202612
- Lazy form
- {n}? is legal and has no effect, n is already exact
- Invalid braces
- JavaScript treats a brace sequence that is not a quantifier as literal text
In detail
Fixed width tokens are what this quantifier is for: a four digit year, a two digit month, six hex digits in a colour, twelve in the last field of a UUID. Where the length is genuinely fixed, an exact count documents the format better than a plus does and rules out a whole category of malformed input for free.
The trap is that an exact count is not an anchor. /\d{4}/ matches the first four digits of "202612" and reports success, because nothing in the pattern says the digits have to stop. A format check needs ^ and $ around it, or a word boundary on each side if the value is embedded in longer text.
Applied to a capture group the quantifier does something people rarely expect. /(\d){3}/ against "123" matches all three digits, but group one holds only the string 3, because each iteration overwrites the previous capture. If you want the whole run, the quantifier belongs inside the group: /(\d{3})/.
Braces that do not parse as a quantifier are not an error in JavaScript, they are literal text. That is a mixed blessing: a typo in the count silently becomes a search for the characters you typed, and a genuine literal brace in a pattern does not always need escaping. When the braces are meant literally, escaping them anyway makes the intent obvious.
Examples
/^\d{4}$/.test("2026"); // true
/^\d{4}$/.test("20260"); // false
/\d{4}/.exec("202612")[0]; // "2026", no anchors, so a prefix is enoughconst a = /(\d){3}/.exec("123");
a[0]; // "123"
a[1]; // "3"
const b = /(\d{3})/.exec("123");
b[1]; // "123"Things that catch people out
- An exact count anchors nothing. /\d{4}/ succeeds on a six digit string, so a format check written this way passes input it should reject.
- Quantifying a capture group keeps only the last repetition. Move the quantifier inside the group when you want the whole run back.
- A malformed count such as {4a} is not a syntax error in JavaScript. It becomes literal text, so the pattern silently searches for the characters instead of counting anything.
Try it: Regex Tester
Type a pattern and a test string, watch every match highlight as you go, read a plain English breakdown of each token, and check the numbered and named groups it captured.
Regex Tester
LOCAL · Browser-OnlyTest and debug regular expressions with live matching and highlights
Related Regex syntax
All regex syntax →{n,m}: bounded repetition between two counts
A bounded count is inclusive at both ends and greedy toward the maximum. JavaScript has no {,m} shorthand, and writing one produces literal text.
{n,}: at least n repetitions, with no upper bound
The open ended count covers everything * and + cannot express, and a stray space after the comma turns the whole quantifier into literal text.
(...) capturing groups: numbering and what comes back
How capture groups are numbered, what a group that did not participate returns, and why quantifying a group throws away everything but the last pass.
Lazy quantifiers: *?, +?, ?? and {n,m}?
A trailing question mark makes a quantifier prefer the shortest match. It fixes the overreaching tag pattern, and a negated class often fixes it better still.
Atomic groups in JavaScript: emulating them with a lookahead
JavaScript has no (?>...) and no possessive quantifiers. The lookahead and backreference pair gives you the same no backtracking behaviour.
Catastrophic backtracking: why a regex freezes a page
Nested quantifiers over overlapping characters make the work grow exponentially with input length. Here is the shape that causes it and the rewrites for it.
Tools for this
- Regex Tester Free online regex tester - test and debug regular expressions with live matching and highlights
- Regex Playground Regex playground with live match highlighting, named groups, find and replace, and shareable links