Skip to content

(?>…) — once matched, never given back

One line: An atomic group matches its contents and then discards every backtracking position inside them, so the engine can fail the whole group but never try a shorter match of it; Python 3.11+, Perl, PCRE2, Ruby, Java and fancy-regex have it, JavaScript, Go and Rust's regex refuse it, and (?=(…))\1 rebuilds it out of parts JavaScript does have.

Level: reference · one construct, eight engines

What it means

(?>a+)a can never match anything. a+ inside the group takes every a it can; the group closes and the positions are gone; the final a finds nothing left, and there is no way back inside to release one. The same pattern without the (?> — a+a — matches aa by giving one back.

That is both the feature and the warning. Atomic groups cut a backtracking search dead, which is what makes catastrophic patterns answer; they also change which strings match, which is what makes an "optimised" pattern stop working. x++ is shorthand for (?>x+), and the possessive quantifier page is the same lesson in that spelling.

Measured

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

construct             python  perl  node  ruby  java  go  rust  fancy
(?>a+)a cannot match  no      no    -     no    no    -   -     no
a+a can               aa      aa    aa    aa    aa    aa  aa    aa
atomic then other     aab     aab   -     aab   aab   -   -     aab
lookahead emulation   no      no    no    no    no    -   -     no

Reading the table

  • Row 1. (?>a+)a on aa: no in Python, Perl, Ruby, Java and fancy-regex. JavaScript, Go and Rust's regex refuse to compile the group — Rust's parser reads (?> as an inline-flag group with an unknown flag.
  • Row 2. a+a, the same pattern without the atomic group, matches aa everywhere. This is the row that proves rows 1 and 3 are about semantics, not syntax.
  • Row 3. (?>a+)b on aab matches aab in all five engines that have the construct: when what follows cannot overlap what is inside, atomic is invisible.
  • Row 4, the emulation. (?=(a+))\1a — a lookahead that captures all the as, then a backreference that consumes them, then a — answers no in every engine with lookahead, JavaScript included. The lookahead cannot be backtracked into, so the backreference holds everything, and the trailing a fails exactly as it did in row 1. That is an atomic group built in JavaScript, and the lesson shows it stopping a catastrophic pattern too.

The trap

Using it as a speed-up without checking the overlap. (?>[\w.]+)\.com on example.com: the group eats example.com whole, the \.com finds nothing, and a pattern that validated correctly yesterday rejects every input today. Atomic is safe when the character after the group cannot appear inside it; when it can, it is a different pattern.

Where it is measured in depth

See also