Why does the =~ operator only sometimes have side effects?
I've noticed a side effect in Ruby/Oniguruma that is only present in 1 out of 4 seemingly equivalent statements. Why is the variable day
defined in 009
, but not in 003
, 005
or 007
?
irb(main):001:0> r = /(?<day>\d\d):(?<mo开发者_JS百科n>\d\d)/
=> /(?<day>\d\d):(?<mon>\d\d)/
irb(main):002:0> r =~ "24:12"
=> 0
irb(main):003:0> day
NameError: undefined local variable or method `day'
irb(main):004:0> "24:12" =~ r
=> 0
irb(main):005:0> day
NameError: undefined local variable or method `day'
irb(main):006:0> "24:12" =~ /(?<day>\d\d):(?<mon>\d\d)/
=> 0
irb(main):007:0> day
NameError: undefined local variable or method `day'
irb(main):008:0> /(?<day>\d\d):(?<mon>\d\d)/ =~ "24:12"
=> 0
irb(main):009:0> day
=> "24"
nb#1: It's the same regex and the same string in all four cases.
nb#2: I've verified the behavior in MS Windows and Ubuntu Linux.
When you call "24:12" =~ r
you actually call "24:12".=~(r)
. So, String#=~ just returns the position the match starts, or nil if there is no match.
But when you call /(?<day>\d\d):(?<mon>\d\d)/ =~ "24:12"
you actually call Regexp#=~
And as the documentation says
If =~ is used with a regexp literal with named captures, captured strings (or nil) is assigned to local variables named by the capture names.
what about 003
:
The assignment is not occur if the regexp is not a literal.
re = /(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/
re =~ " x = y "
p lhs # undefined local variable
p rhs # undefined local variable
and
The assignment is not occur if the regexp is placed at right hand side.
" x = y " =~/(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/
p lhs, rhs # undefined local variable
I believe 003 isn't supported because it's a full blown Regexp object in Rubyland at that point, possibly with overridden methods and such. That makes the scope of assigned locals a lot more complicated.
精彩评论