Skip to content

(?(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>, tag for tag, and no for the unclosed <tag — in Python, Perl, Ruby and fancy-regex. Python has conditionals, which is the thing most people get wrong about it. JavaScript, Java, Go and Rust's regex refuse 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. And fancy-regex gives no on 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

See also