Say you have the string 1280x720@24-30-60 and you want every number inside it: 1280, 720, 24, 30, 60. Not single digits this time — whole runs of them.
A single digit is pattern:\d. But a “number” is a run of one or more digits stuck together. To say how many of something you want, you attach a quantifier to the pattern.
\d
what to match
{3,5}
how many times
A quantifier is a suffix that describes repetition of whatever comes right before it.
Quantity {n}
The most explicit quantifier is a number in curly braces: pattern:{n}. You write it right after the thing you want to repeat, and it says exactly how many copies you need.
There are a few forms. Here they are with examples.
Exact count: pattern:{5}
pattern:\d{5} means five digits in a row — identical to typing pattern:\d\d\d\d\d, only shorter and easier to read.
alert( "the vault code is 48127".match(/\d{5}/) ); // "48127"
That pattern happily matches five digits inside a longer run too. If you want a number that is exactly five digits and no more, wrap it in word boundaries: pattern:\b\d{5}\b. The pattern:\b refuses to sit in the middle of a digit run, so 487219 no longer counts.
\d{5} against “487219”
487219
matches “48721”, ignores the trailing 9
\b\d{5}\b against “487219”
487219
no match — the run is six digits, not five
\d{5} matches any five-digit slice; \b\d{5}\b demands the run be exactly five long.
Range: pattern:{3,5} — 3 to 5 times
Put two numbers in the braces to allow a range. pattern:\d{3,5} matches any run of three, four, or five digits:
alert( "only 12 fit, but 4820 remain".match(/\d{3,5}/) ); // "4820"
12 is skipped because two digits is below the lower bound. 4820 fits, so it wins.
Drop the upper number and keep the comma, and you set only a floor. pattern:\d{3,} means “three digits or more, no ceiling”:
alert( "we had 12, now 872015".match(/\d{3,}/) ); // "872015"
Back to 1280x720@24-30-60. A number is one or more digits, which is pattern:\d{1,} — a floor of one, no ceiling:
let str = "1280x720@24-30-60";let numbers = str.match(/\d{1,}/g);alert(numbers); // 1280,720,24,30,60
The g flag makes match collect every run instead of stopping at the first. Each separator (the x, the @, and the dashes) breaks the digit run, so you get the five groups you were after.
Try the brace forms yourself. Pick a quantifier for pattern:\d and watch which digit runs light up — notice how {2} grabs exactly two at a time while the range and open-ended forms stretch to fill the run.
interactiveAttach a quantifier to \d and see what matches
Live example — Attach a quantifier to \d and see what matches
var txt = document.getElementById('txt');
var q = document.getElementById('q');
var out = document.getElementById('out');
function esc(s) {
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
}
function run() {
var pattern = '\\d' + q.value;
var re;
try {
re = new RegExp(pattern, 'g');
} catch (e) {
out.innerHTML = '<div class="pat">invalid pattern</div>';
return;
}
var s = txt.value;
var result = '', last = 0, count = 0, m;
while ((m = re.exec(s)) !== null) {
if (m.index === re.lastIndex) { re.lastIndex++; continue; }
result += esc(s.slice(last, m.index));
result += '<mark>' + esc(m[0]) + '</mark>';
last = m.index + m[0].length;
count++;
}
result += esc(s.slice(last));
out.innerHTML =
'<div class="pat">/\\d' + esc(q.value) + '/g</div>' +
'<div class="res">' + result + '</div>' +
'<div class="cnt">' + count + (count === 1 ? ' match' : ' matches') + '</div>';
}
txt.addEventListener('input', run);
q.addEventListener('change', run);
run();
Shorthands
Three of these repetition counts show up constantly, so regexp gives each a single-character shorthand. They mean exactly the same as their brace forms — just less typing.
shorthand
same as
meaning
+
{1,}
one or more
?
{0,1}
zero or one (optional)
*
{0,}
zero or more
The three shorthand quantifiers and the brace forms they stand in for.
pattern:+ — one or more
pattern:+ is pattern:{1,}: at least one, then as many as are there. So the number-finding regexp from before shrinks to pattern:\d+:
let str = "1280x720@24-30-60";alert( str.match(/\d+/g) ); // 1280,720,24,30,60
Same result as pattern:\d{1,}, and it reads better. pattern:+ is probably the quantifier you will reach for most.
pattern:? — zero or one
pattern:? is pattern:{0,1}: the preceding thing may appear once or not at all. It makes that character optional.
Take pattern:https?. The pattern:s? says the s is allowed but not required, so the pattern matches both the plain match:http and the secure match:https:
let str = "Use http or https for the link?";alert( str.match(/https?/g) ); // http, https
“http”
https?
s skipped
“https”
https
s matched
s? lets the match go through with the s present or absent.
Flip the switch below to see what the pattern:? buys you. With it off, the pattern is a rigid pattern:https and only the secure form lights up. Turn it on and the s becomes optional, so match:http matches too.
interactiveMake the s optional with ?
Live example — Make the s optional with ?
HTML
<label class="toggle">
<input type="checkbox" id="opt" checked /> make the "s" optional (https<b>?</b>)
</label>
<div class="pat" id="pat"></div>
<div class="res" id="out"></div>
var opt = document.getElementById('opt');
var pat = document.getElementById('pat');
var out = document.getElementById('out');
var text = 'Some links use http, secure ones use https.';
function esc(s) {
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
}
function run() {
var source = opt.checked ? 'https?' : 'https';
var re = new RegExp(source, 'gi');
pat.textContent = '/' + source + '/gi';
var result = '', last = 0, m;
while ((m = re.exec(text)) !== null) {
if (m.index === re.lastIndex) { re.lastIndex++; continue; }
result += esc(text.slice(last, m.index));
result += '<mark>' + esc(m[0]) + '</mark>';
last = m.index + m[0].length;
}
result += esc(text.slice(last));
out.innerHTML = result;
}
opt.addEventListener('change', run);
run();
pattern:* — zero or more
pattern:* is pattern:{0,}: the thing may repeat any number of times, including zero. It is the loosest of the three.
pattern:go* reads as “a g, then any number of os (maybe none)”:
alert( "g go goo".match(/go*/g) ); // g, go, goo
Every one matches, even the lone g, because pattern:o* is satisfied by zero o’s.
Swap pattern:* for pattern:+ and the meaning shifts. pattern:o+ now requires at least one o:
alert( "g go goo".match(/go+/g) ); // go, goo// g is not matched, because o+ requires at least one o
Toggle between the two below. Both patterns start with pattern:g; the only change is the trailing quantifier on o. Watch the lone g blink in and out of the results as you switch — that single character is the entire difference between pattern:* and pattern:+.
var starBtn = document.getElementById('star');
var plusBtn = document.getElementById('plus');
var pat = document.getElementById('pat');
var out = document.getElementById('out');
var cnt = document.getElementById('cnt');
var text = 'g go goo';
var useStar = true;
function esc(s) {
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
}
function run() {
var source = useStar ? 'go*' : 'go+';
var label = useStar ? '/go*/g' : '/go+/g';
var re = new RegExp(source, 'g');
pat.textContent = label;
var result = '', last = 0, count = 0, m;
while ((m = re.exec(text)) !== null) {
if (m.index === re.lastIndex) { re.lastIndex++; continue; }
result += esc(text.slice(last, m.index));
result += '<mark>' + esc(m[0]) + '</mark>';
last = m.index + m[0].length;
count++;
}
result += esc(text.slice(last));
out.innerHTML = result;
cnt.textContent = count + (count === 1 ? ' match' : ' matches') +
(useStar ? " — the lone g counts, since o* allows zero o's" : ' — the lone g is skipped, since o+ needs an o');
starBtn.className = useStar ? 'on' : '';
plusBtn.className = useStar ? '' : 'on';
}
starBtn.addEventListener('click', function () { useStar = true; run(); });
plusBtn.addEventListener('click', function () { useStar = false; run(); });
run();
More examples
Quantifiers are the workhorses of regular expressions — the main building block once patterns get real. A few more to make them stick.
Decimal fractions — a number with a floating point: pattern:\d+\.\d+
Read it left to right: one or more digits, a literal dot (escaped as pattern:\. so it means an actual period, not “any character”), then one or more digits again. Plain integers like 6, 40, and 2200 have no dot, so they are skipped; only 18.75 fits the shape.
An opening HTML tag with no attributes, like <main> or <p>.
It looks for a pattern:<, then one or more Latin letters, then a pattern:>. The i flag makes it case-insensitive so <MAIN> would match too.
That version misses tags like <h2>, because it allows only letters. Per the HTML spec, a tag name may hold a digit anywhere except the first character. So allow a leading letter followed by any mix of letters and digits: pattern:/<[a-z][a-z0-9]*>/i
Here pattern:[a-z] locks the first character to a letter, and pattern:[a-z0-9]* lets the rest be zero or more letters or digits. The pattern:* (not pattern:+) matters — a one-character tag like <b> has nothing after its first letter, and pattern:* is fine with that.
Breaking down <[a-z][a-z0-9]*> against the tag <h2>.
Opening or closing tag without attributes: pattern:/<\/?[a-z][a-z0-9]*>/i
To catch closing tags too, allow an optional slash right after the pattern:<. That is pattern:\/? — a slash made optional by pattern:?. The slash is escaped with a backslash because an unescaped / inside a regexp literal would end the pattern early.