C.W.K.
Stream
Lesson 11 of 12 · published

Conditional Patterns — (?(N)yes|no)

~8 min · conditional, advanced, pcre

Level 0Pattern-Curious
0 XP0/90 lessons0/15 achievements
0/100 XP to next level100 XP to go0% complete

Match different patterns based on whether a group captured

Conditional patterns let you say "if group N captured something, match the YES branch; otherwise match the NO branch." Syntax: (?(N)yes|no) where N is a group number, or (?(name)yes|no) for named groups.

This is a niche but powerful feature. It's how you express patterns like "if there's an opening quote, require a matching closing quote; otherwise no quote requirement."

Worked example: optional bracket pairing

Pattern: (\()?\d+(?(1)\)) — "optional opening paren, then digits, then matching closing paren ONLY if we had an opener."

  • Matches 123 (no parens, both fine)
  • Matches (123) (open + close)
  • Does NOT match (123 or 123) (mismatched)

Flavor support

Conditionals are a PCRE feature, supported by Python re, Perl, .NET, PHP, Ruby (via Regexp::Engine). They're NOT in JavaScript, Go, or RE2.

When to reach for them

Honestly, rarely. Most patterns that benefit from conditionals can be cleaner as alternation: (?:\(\d+\)|\d+) matches the same thing as the conditional above and works in every flavor. Reach for conditionals only when the YES branch is much more complex than the NO branch and you want to avoid duplication.

Code

Conditional patterns·python
import re

# Bracket pair: open and close together, or neither
pattern = r'(\()?\d+(?(1)\))'
bool(re.fullmatch(pattern, '123'))    # True
bool(re.fullmatch(pattern, '(123)'))  # True
bool(re.fullmatch(pattern, '(123'))   # False
bool(re.fullmatch(pattern, '123)'))   # False

# Named group conditional
pattern = r'(?P<bracket>\()?\d+(?(bracket)\))'
bool(re.fullmatch(pattern, '(42)'))   # True

# Equivalent without conditional — usually cleaner
pattern = r'\(\d+\)|\d+'
bool(re.fullmatch(pattern, '(42)'))   # True
bool(re.fullmatch(pattern, '42'))     # True

External links

Exercise

Write a pattern that matches a phone number that's either fully wrapped in parens like (415-555-0199) or fully bare 415-555-0199 — but NOT one paren without the other. Solve it with alternation; then solve it again with a conditional. Compare readability.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.