X Xerobit

Regex Quantifiers — *, +, ?, {n}, and Greedy vs Lazy Matching

Regex quantifiers control how many times a pattern matches: * (zero or more), + (one or more), ? (zero or one), {n,m} (specific range). Here's how each quantifier works and...

Mian Ali Khalid · · 4 min read
Use the tool
Regex Tester
Test regular expressions with live match highlighting and explanation.
Open Regex Tester →

Quantifiers specify how many times a pattern element must match. Misusing them is the most common source of regex bugs — especially the difference between greedy and lazy matching.

Use the Regex Tester to test quantifier patterns on real text.

The quantifiers

QuantifierMeaningMatches
*Zero or more“ or a or aaa
+One or morea or aaa (not empty)
?Zero or one“ or a
{n}Exactly naaa for {3}
{n,}n or moreaaa, aaaa, etc.
{n,m}Between n and maa, aaa for {2,3}

* (zero or more)

/ab*c/.test('ac')     // true  (zero b's)
/ab*c/.test('abc')    // true  (one b)
/ab*c/.test('abbbc')  // true  (three b's)
/ab*c/.test('adc')    // false (d not b)

// Common pattern — match anything:
/a.*z/  // 'a' followed by anything, ending in 'z'
'abcdefz'.match(/a.*z/)  // ['abcdefz']

+ (one or more)

/\d+/.test('123')    // true
/\d+/.test('')       // false
/\d+/.test('abc')    // false

// Extract numbers from text:
'I have 3 cats and 12 dogs'.match(/\d+/g)  // ['3', '12']

// Difference from *:
/\d*/.test('')   // true (zero digits)
/\d+/.test('')   // false (needs at least one)

? (zero or one — optional)

// Make a character optional:
/colou?r/.test('color')   // true (u optional)
/colou?r/.test('colour')  // true

// Optional group:
/https?:\/\//.test('http://example.com')   // true
/https?:\/\//.test('https://example.com')  // true

// Phone number with optional country code:
/(\+1)?[ -]?\d{3}[ -]?\d{3}[ -]?\d{4}/

{n,m} (range)

// Exactly 5 digits:
/^\d{5}$/.test('12345')    // true
/^\d{5}$/.test('1234')     // false (only 4)
/^\d{5}$/.test('123456')   // false (6 digits)

// 2 to 4 characters:
/^[a-z]{2,4}$/.test('ab')    // true
/^[a-z]{2,4}$/.test('abcd')  // true
/^[a-z]{2,4}$/.test('abcde') // false

// US zip code (5 digits, optional 4-digit extension):
/^\d{5}(-\d{4})?$/

Greedy vs lazy matching

By default, quantifiers are greedy — they match as much as possible while still allowing the overall pattern to succeed.

const html = '<b>bold</b> and <b>also bold</b>';

// Greedy (default):
html.match(/<b>.*<\/b>/)
// ['<b>bold</b> and <b>also bold</b>']
// Matches from first <b> to LAST </b>

// Lazy (add ?):
html.match(/<b>.*?<\/b>/)
// ['<b>bold</b>']
// Matches shortest possible string

Add ? after any quantifier to make it lazy:

GreedyLazyMeaning
**?Zero or more, lazy
++?One or more, lazy
???Zero or one, lazy
{n,m}{n,m}?Range, lazy

Practical lazy matching examples

// Extract content inside HTML tags:
'<title>My Page</title>'.match(/<title>(.*?)<\/title>/)[1]
// 'My Page'

// Extract all items in quotes:
'"apple" and "banana"'.match(/"[^"]*"/g)
// ['"apple"', '"banana"']
// (using negated character class is better than .*? for quotes)

// JSON string value (handles escaped quotes):
/"(?:[^"\\]|\\.)*"/.exec('"hello \\"world\\""')[0]
// '"hello \"world\""'

Possessive quantifiers (atomic groups)

Some regex engines support possessive quantifiers (*+, ++, ?+) that don’t backtrack:

// JavaScript doesn't have possessive quantifiers directly
// Use atomic groups via a workaround or different engine

// Python (3.11+) supports possessive:
// \d++ — match digits without backtracking

Catastrophic backtracking

Nested quantifiers on overlapping patterns can cause exponential backtracking:

// DANGEROUS — catastrophic backtracking:
/^(a+)+$/.test('aaaaaaaaaaaaaaaaaaaaaaaaaaab')
// This can take seconds or minutes!

// WHY: (a+)+ tries every way to split the a's among groups
// then fails the final b check, backtracks, tries again...

// SAFER: be more specific
/^a+$/.test('aaaaaaaaab')  // Immediately fails

Always test regexes with input that should fail — that’s when catastrophic backtracking strikes.


Related posts

Related tool

Regex Tester

Test regular expressions with live match highlighting and explanation.

Written by Mian Ali Khalid. Part of the Dev Productivity pillar.