skrobul
skrobul

Reputation: 182

Named capture in Ruby's regular expressions

I am trying to extract information from a line of text with relatively long regular expression. Below is a simplified regexp that describes the problem.

line = "Internet  10.9.68.178           127   c07b.bce9.7d41  ARPA   Vlan2"

If I try to match this line directly without trying to 'save' regexp into a variable, it works very well:

[223] pry(main)> /Internet\s+(?<ipaddr>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/  =~ line
=> 0
[224] pry(main)> ipaddr
=> "10.9.68.178"
[225] pry(main)> $1
=> "10.9.68.178"

Now, when I try to do exact same thing with 'stored' version of the regexp, it fails miserably:

  [226] pry(main)> ipaddr = nil   # ensure that it's cleared before match

  [227] pry(main)> myreg = /Internet\s+(?<ipaddr>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/
  => /Internet\s+(?<ipaddr>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/
  [228] pry(main)> myreg =~ line
  => 0
  [229] pry(main)> ipaddr
  => nil
  [230] pry(main)> $1
  => "10.9.68.178"

I have also tried to call match method directly and it seems to work:

[231] pry(main)> myreg.match(line)
=> #<MatchData "Internet  10.9.68.178" ipaddr:"10.9.68.178">

but this means for a simple if statement I need to do something like this:

if m = myreg.match(line)
   do_stuff m[:ipaddr]
end

instead of simply

if myreg =~ line
   do_stuff ipaddr
end

Any ideas as to why the names are not captured correctly in this instance?

Upvotes: 1

Views: 92

Answers (1)

Cristian Lupascu
Cristian Lupascu

Reputation: 40526

Interesting. I've looked this up in the Ruby Documentation.

It says there:

The assignment does not occur if the regexp is not a literal.

That's why /Internet\s+(?<ipaddr>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/ =~ line works, but myreg =~ line does not.

Thanks for making me learn something new. :)

Upvotes: 1

Related Questions