Feature #16796
closedAssigning local variables when using `case when regexp`
Description
I want to use
case "str"
when /s(?<mid>.)r/
p mid
end
instead of
case
when /s(?<mid>.)r/ =~ "str"
p mid
end
I also do not like using $1
.
This feature is extremely useful when there are a lot of when
s.
Updated by nobu (Nobuyoshi Nakada) about 4 years ago
It is because when
calls ===
method but not =~
.
Updated by sawa (Tsuyoshi Sawada) about 4 years ago
I have met such use cases, and agree this would be useful.
Alternatively, in order to access even unnamed matches, assigning the last matched data to a variable with the following syntax may be useful.
case "str"
when /s(?<mid>.)r/ => match_data
match_data[:mid] # => "t"
end
case "str"
when /s(.)r/ => match_data
match_data[1] # => "t"
end
Updated by shyouhei (Shyouhei Urabe) about 4 years ago
sawa (Tsuyoshi Sawada) wrote in #note-2:
Alternatively, in order to access even unnamed matches, assigning the last matched data to a variable with the following syntax may be useful.
case "str" when /s(.)r/ => match_data match_data[1] # => "t" end
That's too confusing. The following code works today.
case "str"
in /s(.)r/ => match_data
match_data[1] # => "t"
end
Updated by shevegen (Robert A. Heiler) about 4 years ago
sawa wrote:
I have met such use cases, and agree this would be useful.
I don't disagree in the sense that there may be valid use cases,
but the syntax is kind of weird:
/s(?<mid>.)r/
I use regexes a lot of course, since they are useful. But do we
really gain a lot from making what used to be simple, harder?
I understand that you may avoid an extra step (assignment, after
the regex match), but to me personally I find that style so
much harder to read, compared to:
if /(foo.+)/
mid = $1.to_s.dup # or something like that
end
Admittedly I am very much a very oldschool-ruby person. ;)
By the way, while I personally do not really like $ variables,
I actually use them a LOT, whereas I rarely use match_data[]
syntax style. Dunno why, perhaps a habit, but the $1 $2 etc..
are ony of the few (semi) global variables that I like.
(I write "semi" because they tend to be more volatile, which
is why I may tend to use .dup like a semi-crazy person a
lot, rather than fix a regex or handle nils - I .to_s.dup
all the things! ;) )
Updated by matz (Yukihiro Matsumoto) about 4 years ago
- Status changed from Open to Rejected
Implicit assignment from regular expression matches has been a bad idea. I shouldn't have merged it at the first moment.
I'd like to remove it altogether if I have a chance. So I don't like to enhance it any further.
Matz.
Updated by milouse (Étienne Deparis) over 1 year ago
shyouhei (Shyouhei Urabe) wrote in #note-3:
sawa (Tsuyoshi Sawada) wrote in #note-2:
That's too confusing. The following code works today.
case "str" in /s(.)r/ => match_data match_data[1] # => "t" end
Not really (or at least it is not what I understand from the original request, as I felt on a similar issue today). You are just pointing out an edge case where match_data[1]
will be t
, not because it is actually a MatchData
object, which first capturing group worth t
, but just because the pattern matching feature select this branch and put the original String
"str" onto match_data
. Thus match_data[1]
here only gives you the second char of the string match_data
.
The previous example would have fail (in my understanding of the problem), with the following regexp:
case "str"
in /(.)tr/ => match_data
match_data[1] # => "t" instead of the expected "s"
end
By the way, there is in fact a very simple way to achieve the initial goal (again, from my understanding of the problem):
case "str"
when /s(?<mid>.)r/
match_data = Regexp.last_match
p match_data[:mid]
end