Regular Expressions › Quantifiers: How Many Times?
Language AI HandbookAll chapters Regular Expressions › Quantifiers: How Many Times?One section · Sections in this chapter5 / 21 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Quantifiers specify how many times the preceding element should match. They range from simple repetition (*, +, ?) to precise bounds ({n}, {n,m}). Understanding quantifiers is essential because they determine whether your pattern matches once, multiple times, or not at all.
Every quantifier attaches to the immediately preceding element, which can be a literal character, a character class, a shorthand class, or a group enclosed in parentheses. This is a common source of confusion: in ab+, the + applies only to b, so the pattern matches "ab", "abb", "abbb", and so on, but not "aab". If you want to repeat "ab" as a unit, you need (ab)+. Understanding what element a quantifier is attached to is the first step to reading any complex pattern correctly.
Basic Quantifiers
text = "a aa aaa aaaa b bb bbb"
# * = zero or more
star = re.findall(r"ba*", "b ba baa baaa")
# + = one or more
plus = re.findall(r"ba+", "b ba baa baaa")
# ? = zero or one (optional)
optional = re.findall(r"colou?r", "color colour")
# {n} = exactly n times
exact = re.findall(r"a{3}", text)
# {n,m} = between n and m times
range_q = re.findall(r"a{2,3}", text)
# {n,} = n or more times
at_least = re.findall(r"a{2,}", text)Quantifier examples:
* (zero or more):
Pattern: ba* Text: 'b ba baa baaa'
Matches: ['b', 'ba', 'baa', 'baaa']
+ (one or more):
Pattern: ba+ Text: 'b ba baa baaa'
Matches: ['ba', 'baa', 'baaa']
? (zero or one):
Pattern: colou?r Text: 'color colour'
Matches: ['color', 'colour']
{n} (exactly n):
Pattern: a{3} Text: 'a aa aaa aaaa b bb bbb'
Matches: ['aaa', 'aaa']
{n,m} (between n and m):
Pattern: a{2,3} Text: 'a aa aaa aaaa b bb bbb'
Matches: ['aa', 'aaa', 'aaa']
The visualization shows how quantifiers dramatically affect matching behavior. Notice that ba* finds 5 matches because it accepts zero 'a's (matching just 'b'), while ba+ finds only 4 because it requires at least one 'a'. The bounded quantifiers {2}, {2,3}, and {2,} are more selective, matching only strings with specific repetition counts.
Greedy vs. Lazy Matching
By default, quantifiers are greedy: they match as much as possible. Adding ? after a quantifier makes it lazy, matching as little as possible.
html = "<div>Hello</div><div>World</div>"
# Greedy: matches as much as possible
greedy = re.findall(r"<div>.*</div>", html)
# Lazy: matches as little as possible
lazy = re.findall(r"<div>.*?</div>", html)HTML: '<div>Hello</div><div>World</div>' Greedy (.*) - matches maximum: Pattern: <div>.*</div> Matches: ['<div>Hello</div><div>World</div>'] Lazy (.*?) - matches minimum: Pattern: <div>.*?</div> Matches: ['<div>Hello</div>', '<div>World</div>']
The greedy pattern matched from the first <div> all the way to the last </div>, consuming both tags. The lazy pattern stopped at the first </div> it found, giving us each tag separately. This distinction is critical when parsing structured text.
The reason greedy matching is the default is efficiency. A greedy quantifier starts by consuming as much as possible and then backs off only when necessary to complete the overall match. In many patterns this is exactly what you want. But when your pattern has two possible "endpoints" in the string, a greedy quantifier will race to the furthest one. The practical rule of thumb: if you are matching text between delimiters (tags, quotes, brackets), use lazy quantifiers to get the shortest match between each pair of delimiters. If you are matching everything up to a specific character class, greedy is usually fine because the character class itself acts as a natural stop.
Notice that you make a quantifier lazy by adding a ? after it: *?, +?, {n,m}?. The ? is doing double duty in regex: after a character or class it means "zero or one occurrence," but after another quantifier it means "use the lazy strategy." Context determines which interpretation applies.

