(?:…) — a group that does not count¶
One line: (?:…) groups a sub-pattern for a quantifier or an alternation without creating a capture, so the groups after it keep their numbers; the same bracket grew a flag slot — (?i:…) — that turns an option on for exactly that group, in every engine here except JavaScript at ES2018.
Level: reference · one construct, eight engines
What it means¶
Every ( costs something: a number, and in a backtracking engine a little bookkeeping. (?: buys the grouping without the capture. Use it whenever the group exists to hold a quantifier or an alternation and nobody will ask what it matched — which is most groups in most patterns.
The scoped-flag form is the same construct with a flag between ? and :. (?i:ab)c matches ab in either case and c in lowercase only; (?-i:…) turns a flag off inside the group.
Measured¶
Verified output of kw_non_capturing_group_sh.sh — regenerated by tools/run_examples.py, never hand-typed.
construct python perl node ruby java go rust fancy
grouping only abab abab abab abab abab abab abab abab
does not shift numbers $1 b b $1 b b b b
does not shift, \1 b \u{1} \\1 b 1 \\1 \\1 \\1
scoped flag (?i:) Ab Ab n/a Ab Ab Ab Ab Ab
scoped flag off (?-i:) no no n/a no no no no no
Reading the table¶
- Row 1. Quantifying a non-capturing group works exactly like quantifying a capturing one.
- Rows 2–3, numbering.
(?:a)(b)— thebis group 1, because the group before it does not count.$1givesbin Perl, JavaScript, Java, Go and Rust;\1givesbin Python and Ruby. The other cells are the replacement spelling story, not a numbering one. - Rows 4–5, scoped flags.
(?i:a)bonAb: matches in all seven engines asked, and(?i)a(?-i:b)onABfails in all seven, becausebwas made case-sensitive again inside its group. JavaScript isn/aon both rows by design: inline modifier groups arrived in JavaScript after ES2018, and Node 20 (where these tables were made) and Node 24 (where CI checks them) disagree about them, so the driver was told not to ask. As of ES2018 the answer is "refused".
The trap¶
Forgetting the ?: and then counting groups. A pattern with six brackets where two are (?: has four capture groups, and a $5 in the replacement is an error in Java, empty in Go and Rust, and the literal text $5 in Python and Ruby. The capturing group page has the numbering rule; the fix in any engine larger than a one-liner is names.
Where it is measured in depth¶
- Flags, and where you can turn one on — scoped flags per engine, and the mid-pattern
(?i)that most engines scope to the enclosing group.
See also¶
- Capturing group · Named group · Atomic group
(?>…)— the other things a(?can start. - Inline flags.
- Performance — what a capture costs.