Named captures become local variables — sometimes¶
Level: 201 · anyone who has seen a variable appear out of a regex
One line: /(?<year>\d+)/ =~ text creates a local variable year, but only when a regex literal without interpolation is on the left of =~; in any other arrangement no variable appears, and a match that fails sets an existing variable of the same name to nil.
The shortcut is decided by the parser, when it reads the file, not when the match runs: the parser has to see the group names in the source to know which variables to create. Everything that hides the names from the parser turns the shortcut off, silently.
Verified output of named_captures_become_variables_rb.rb — regenerated by tools/run_examples.py, never hand-typed.
literal on the left of =~ year="2025" month="12"
regex held in a variable defined?(day) is nil
string on the left of =~ defined?(century) is nil
literal with an interpolation defined?(hh) is nil
...but $~ holds the match $~[:hh] is "12"
an existing local, no match label is nil
MatchData works in every case m[:year] is "2025", named_captures {"year" => "2025", "month" => "12"}
Reading the output¶
- Literal on the left:
yearandmonthexist after the match. - Regex in a variable: the parser cannot see inside
pattern, so there is noday. Code that referred todaywould raiseNameError. - String on the left:
"2026" =~ regexcallsString#=~, and the shortcut belongs to the regex literal form only. - Interpolation: the names could depend on a run-time value, so no variables — but
$~still holds the match. - A failed match assigns
nil.labelheld"kept", the pattern names a grouplabel, the match failed, and the variable was overwritten.
What to do¶
Read captures from a MatchData — m = text.match(re), then m[:year] or m.named_captures — which works in every arrangement above. If you use the literal-on-the-left form, give groups names that no variable nearby already has.
If you are coming from another language¶
Perl never makes variables from group names; a successful match fills the %+ hash:
Verified output of named_captures_become_variables_pl.pl — regenerated by tools/run_examples.py, never hand-typed.
Python spells the group (?P<name>...) and keeps the result on the match object:
Verified output of named_captures_become_variables_py.py — regenerated by tools/run_examples.py, never hand-typed.