Using Named Captures with Regex Match in Ruby's Case...When

Using Named Captures with regex match in Ruby's case...when?

named captures set local variables when this syntax.

regex-literal =~ string

Dosen't set in other syntax. # See rdoc(re.c)

regex-variable =~ string

string =~ regex

regex.match(string)

case string
when regex
else
end

I like named captures too, but I don't like this behavior.
Now, we have to use $~ in case syntax.

case string
when /(?<name>.)/
$~[:name]
else
end

How to write a Ruby switch statement (case...when) with regex and backreferences?

The references to the latest regex matching groups are always stored in pseudo variables $1 to $9:

case foo
when /^([0-9][0-9])/
print "the month is #{$1}"
else
print "something else"
end

You can also use the $LAST_MATCH_INFO pseudo variable to get at the whole MatchData object. This can be useful when using named captures:

case foo
when /^(?<number>[0-9][0-9])/
print "the month is #{$LAST_MATCH_INFO['number']}"
else
print "something else"
end

Regex with named capture groups getting all matches in Ruby

Named captures are suitable only for one matching result.

Ruby's analogue of findall is String#scan. You can either use scan result as an array, or pass a block to it:

irb> s = "123--abc,123--abc,123--abc"
=> "123--abc,123--abc,123--abc"

irb> s.scan(/(\d*)--([a-z]*)/)
=> [["123", "abc"], ["123", "abc"], ["123", "abc"]]

irb> s.scan(/(\d*)--([a-z]*)/) do |number, chars|
irb* p [number,chars]
irb> end
["123", "abc"]
["123", "abc"]
["123", "abc"]
=> "123--abc,123--abc,123--abc"

Ruby Named Capture

style, price, stock = <<~_.scan(/^(?:Style |Price \$|Stock \# )(.+)/).flatten
Style 130690 113
Price $335.00
Stock # 932811
_
# => "130690 113", "335.00", "932811"

Ruby regular expression matching enumerator with named capture support

Very identical to the answer you have already seen, but slightly different.

str = "Sun rises at 6:23 am & sets at 5:45 pm; Moon comes up by 7:20 pm ..."
str.gsub(/(?<time>\d:\d{2}) (?<meridiem>am|pm)/).map{ Regexp.last_match }

#=> [#<MatchData "6:23 am" time:"6:23" meridiem:"am">, #<MatchData "5:45 pm" ...

How to do named capture in ruby

You should use match with named captures, not scan

m = "555-333-7777".match(/(?<area>\d{3})-(?<city>\d{3})-(?<number>\d{4})/)
m # => #<MatchData "555-333-7777" area:"555" city:"333" number:"7777">
m[:area] # => "555"
m[:city] # => "333"

If you want an actual hash, you can use something like this:

m.names.zip(m.captures).to_h # => {"area"=>"555", "city"=>"333", "number"=>"7777"}

Or this (ruby 2.4 or later)

m.named_captures # => {"area"=>"555", "city"=>"333", "number"=>"7777"}

Ruby - best way to extract regex capture groups?

Since v2.4.6, Ruby has had named_captures, which can be used like this. Just add the ?<some_name> syntax inside a capture group.

/(\w)(\w)/.match("ab").captures # => ["a", "b"]
/(\w)(\w)/.match("ab").named_captures # => {}

/(?<some_name>\w)(\w)/.match("ab").captures # => ["a"]
/(?<some_name>\w)(\w)/.match("ab").named_captures # => {"some_name"=>"a"}

Even more relevant, you can reference a named capture by name!

result = /(?<some_name>\w)(\w)/.match("ab")
result["some_name"] # => "a"

Why does capturing named groups in Ruby result in undefined local variable or method errors?

Named Captures Must Use Literals

You are encountering some limitations of Ruby's regular expression library. The Regexp#=~ method limits named captures as follows:

  • The assignment does not occur if the regexp is not a literal.
  • A regexp interpolation, #{}, also disables the assignment.
  • The assignment does not occur if the regexp is placed on the right hand side.

You'll need to decide whether you want named captures or interpolation in your regular expressions. You currently cannot have both.

Ruby regex - gsub only captured group

You can't. gsub replaces the entire match; it does not do anything with the captured groups. It will not make any difference whether the groups are captured or not.

In order to achieve the result, you need to use lookbehind and lookahead.

"5,214".gsub(/(?<=\d),(?=\d)/, '.')

Ruby Regex: How to match (named) groups inside square brackets?

Square brackets are used for "exactly one of any of these characters" -- that's not what you need here. Pattern-level alternation is done via the | operator: (hello|goodbye) world will match either hello world or goodbye world.

(?<offset>Z|[+-]\d{2}:\d{2})?

Specifically to parse a datetime, though, I suggest preferring DateTime.parse (plus to_time, if you need a Time instance). And if that isn't sufficiently flexible, consider the chronic gem.



Related Topics



Leave a reply



Submit