(?>…) — 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+)aonaa:noin Python, Perl, Ruby, Java andfancy-regex. JavaScript, Go and Rust'sregexrefuse 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, matchesaaeverywhere. This is the row that proves rows 1 and 3 are about semantics, not syntax. - Row 3.
(?>a+)bonaabmatchesaabin 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 theas, then a backreference that consumes them, thena— answersnoin every engine with lookahead, JavaScript included. The lookahead cannot be backtracked into, so the backreference holds everything, and the trailingafails 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¶
- Atomic groups and possessive quantifiers — the equivalence, the silent breakage, the cliff with a time cap, and the JavaScript emulation working.
- Catastrophic backtracking — the problem this solves.
See also¶
- Possessive quantifier
*+· Lookahead · Backtracking verbs — finer control over the same search, Perl and PCRE2 only. - Performance.