*, +, ? — zero or more, one or more, at most one¶
One line: The three basic quantifiers apply to the atom before them, are greedy, and behave identically in all eight engines — including the two surprises, that x* succeeds on a subject with no x in it by matching the empty string, and that x** is a compile error in six engines and legal in Ruby and Rust.
Level: reference · one construct, eight engines
What it means¶
| Quantifier | Matches the atom | Same as |
|---|---|---|
x* |
zero or more times | x{0,} |
x+ |
one or more times | x{1,} |
x? |
zero or one time | x{0,1} |
All three are greedy: they take as many repetitions as they can and give them back one at a time if the rest of the pattern fails. The atom is the single thing before the quantifier — a character, a class, an escape, or a group. ab* is a then any number of b; (ab)* is any number of ab.
Measured¶
Verified output of kw_star_plus_question_sh.sh — regenerated by tools/run_examples.py, never hand-typed.
construct python perl node ruby java go rust fancy
b* takes nothing ac ac ac ac ac ac ac ac
b+ needs one no no no no no no no no
b? takes at most one no no no no no no no no
* on a subject with none "" "" "" "" "" "" "" ""
? is greedy too a a a a a a a a
stacked quantifiers x** - - - xx - - xx -
quantifier on nothing - - - - - - - -
quantified group abab abab abab abab abab abab abab abab
Reading the table¶
- Rows 1–3.
b*accepts nothing betweenaandc;b+insists on at least one;b?refuses two. Unanimous, as this part of the syntax has been for forty years. - Row 4,
x*onabc. Every engine matches — the empty string at offset 0. A search forx*never fails, because zero repetitions is a success. This is the quantifier's most reliable trap:re.findall(r"\d*", "a1b")returns['', '1', '', ''], and areplaceofx*with-puts a dash between every pair of characters. When you mean "some", write+. - Row 5,
a?aona.?is greedy too: it takes thea, the secondafails, it gives the first back, the secondamatches. The overall match isain all eight — but only because the engine backtracked. The lazy??on the lazy quantifier page takes nothing first. - Row 6,
x**. Python, Perl, JavaScript, Java, Go andfancy-regexrefuse a quantifier on a quantifier. Ruby and Rust'sregexaccept it and readx**as(x*)*. Ruby warns; Rust does not. The same is true ofa++— in Ruby that is possessive, in Rust it is(a+)+, and the possessive quantifier page measures what that changes. - Row 7,
*a. A quantifier with nothing before it is refused everywhere. Row 8 is the group case,(ab)+takingababand stopping before thex.
The trap¶
Row 4. * is the quantifier people reach for when they mean "there might be several", and it also means "there might be none", which turns a search into a guaranteed success and an extraction into a list full of empty strings. The second trap is row 6: x** and x+* pass Rust's compiler and Ruby's, so a stray character in a pattern is a legal pattern there.
Where it is measured in depth¶
- Greedy and lazy — the give-back mechanism, measured in read counts.
- Catastrophic backtracking — what a quantifier over a quantifier costs when it is legal.
See also¶
{n,m}— the counted form.- Lazy
*?· Possessive*+— the other two modes. - Capturing group — what a quantified group keeps.