(?(1)yes|no) and (?(DEFINE)…) — a branch that depends on the match so far¶
One line: A conditional runs one sub-pattern if a group has participated in the match and another if it has not — in Python, Perl, PCRE2, Ruby and fancy-regex, and in none of JavaScript, Java, Go or Rust's regex — and the condition can also be a name, a lookaround, or DEFINE, a block that defines named sub-patterns and matches nothing itself.
Level: reference · one construct, eight engines — the lesson has the depth
What it means¶
| Condition | Meaning | Perl / PCRE2 | Python | Ruby | fancy-regex |
|---|---|---|---|---|---|
(?(1)…|…) |
did group 1 match | yes | yes | yes | yes |
(?(<n>)…), (?('n')…) |
did the named group match | yes | no | yes | yes |
(?(n)…) |
the bare name | PCRE2 yes, Perl no | yes | no | compiles, always false |
(?(?=…)…) |
does a lookahead succeed here | yes | no | no | no |
(?(R)…), (?(R1)…) |
are we inside a recursion | yes | no | no | no |
(?(DEFINE)…) |
define sub-patterns, match nothing | yes | no | no | no |
The classic honest use is an optional opening delimiter that makes the closing one mandatory: (<)?\w+(?(1)>) matches <tag> and tag and must not match <tag.
Measured¶
Verified output of kw_conditional_sh.sh — regenerated by tools/run_examples.py, never hand-typed.
construct python perl node ruby java go rust fancy
optional bracket, closed <tag> <tag> - <tag> - - - <tag>
optional bracket, bare tag tag - tag - - - tag
optional bracket, open no no - no - - - no
named condition (?(<n>)) - <tag> - <tag> - - - <tag>
named condition (?(n)) <tag> - - - - - - no
lookahead condition - <tag> - - - - - -
DEFINE block - 5 - - - - - -
Reading the table¶
- Rows 1–3, the delimiter case. Anchored,
^(<)?\w+(?(1)>)$gives<tag>for<tag>,tagfortag, andnofor the unclosed<tag— in Python, Perl, Ruby andfancy-regex. Python has conditionals, which is the thing most people get wrong about it. JavaScript, Java, Go and Rust'sregexrefuse the construct. - Row 4,
(?(<b>)…). The angle-bracket name: Perl, Ruby,fancy-regex. Python refuses — it has no(?<name>syntax to begin with. - Row 5,
(?(b)…), the bare name with(?P<b>…). Python alone answers correctly. Perl refuses the bare form. Andfancy-regexgivesnoon a subject that should match: it compiles(?(b)…), treats the condition as always false, and never says so. That is the only cell on this page where an engine compiles a conditional and silently means something else. - Row 6, a lookahead as the condition. Perl only, among these eight (PCRE2 has it too).
- Row 7,
(?(DEFINE)…). Perl only. The block defines(?<d>\d)and matches nothing;(?&d)then calls it. Combined with(?x)this is how a long PCRE2 pattern gets written as named parts — the closest a regular expression comes to declaring a function.
The trap¶
Numbering, as always: a conditional on (1) silently changes meaning when a group is inserted before it. Use names — and then note that no two engines share a named spelling. The second trap is fancy-regex's row 5, an engine accepting a pattern and inverting its answer.
The judgement: a conditional is usually a sign the problem wanted two patterns and an if in the host language. It earns its place in a single pass over a large input, or in a pattern that must live in a configuration file where there is no host language.
Where it is measured in depth¶
- Conditionals, and the
(?(DEFINE)…)block — every form in every engine, the Perl/PCRE2 disagreement on(?(R)…)when a group is namedR, and the dated pcre2grep run for ABAP.
See also¶
- Recursion and subroutine calls —
(?&d), which DEFINE exists to serve. - Named group · Lookahead · Alternation.
- Readable patterns.