Skip to content

{n}, {n,}, {n,m} — counted repetition, and the two spellings that are not the same everywhere

One line: a{2}, a{2,} and a{1,2} mean exactly, at-least and between in all eight engines; a{,2} (no lower bound) is up-to-two in Python, Perl, Ruby and fancy-regex, a literal a{,2} in JavaScript and Go, and a compile error in Java and Rust; and a bare { that is not a quantifier is a literal in six engines and refused by Java and Rust.

Level: reference · one construct, eight engines

What it means

Form Repetitions Greedy
x{n} exactly n —
x{n,} n or more yes
x{n,m} between n and m yes
x{,m} zero to m — where it is supported yes

Like * and +, a counted quantifier is greedy, takes a ? suffix to become lazy and a + suffix to become possessive, and applies to the single atom before it.

Measured

Verified output of kw_braces_sh.sh — regenerated by tools/run_examples.py, never hand-typed.

construct               python  perl  node  ruby    java  go    rust    fancy
exactly two             aa      aa    aa    aa      aa    aa    aa      aa
two or more             aaaa    aaaa  aaaa  aaaa    aaaa  aaaa  aaaa    aaaa
between one and two     aa      aa    aa    aa      aa    aa    aa      aa
{,2} up to two          aa      aa    no    aa      -     no    -       aa
{2,1} backwards         -       no    -     -       -     -     -       -
{1001} large count      ok      ok    ok    ok      ok    -     ok      ok
{2}{3} stacked          -       -     -     aaaaaa  aa    -     aaaaaa  no
literal brace           a{      a{    a{    a{      -     a{    -       a{
literal brace, escaped  a{      a{    a{    a{      a{    a{    a{      a{

Reading the table

  • Rows 1–3 are unanimous. Row 3 is worth a second look: a{1,2} on aaaa matches aa, the greedy maximum, not the whole run.
  • Row 4, a{,2}. Python, Perl, Ruby and fancy-regex read it as a{0,2} and match aa. JavaScript and Go read it as the literal text a{,2} and answer no — no error, no match, a pattern that is silently a different pattern. Java and Rust's regex refuse it. Write {0,2}; every engine agrees about that.
  • Row 5, a{2,1}. Backwards bounds are refused everywhere — except Perl, which compiles the pattern and answers no. Perl 5.42 accepts {2,1} as a quantifier that can never be satisfied.
  • Row 6, a{1001}. Go refuses: RE2's documented limit is 1000. Everyone else compiles it. A pattern that validates a fixed-width field of 1024 characters is portable to seven of these eight engines.
  • Row 7, a{2}{3}. Stacked counts are refused by Python, Perl, JavaScript and Go. Ruby and Rust's regex compose them — (a{2}){3} — and match six as. Java matches two: it accepts the syntax and the second count does nothing visible here. fancy-regex compiles it and matches nothing at all. Four different answers to a pattern nobody should write.
  • Rows 8–9, a bare {. a{ is a literal in six engines; Java and Rust's regex refuse it. a\{ is a literal everywhere. Escape the brace.

The trap

Row 4 is the one that ships. {,n} is a natural thing to write, it is legal Python and legal Perl, and in JavaScript or Go it turns the quantifier into five ordinary characters. A test that never exercises the "zero occurrences" case passes anyway.

Where it is measured in depth

See also