3

I'm relatively new to ruby and I'm trying to figure out the "ruby" way of extracting multiple values from a string, based on grouping in regexes. I'm using ruby 1.8 (so I don't think I have named captures).

I could just match and then assign $1,$2 - but I feel like there's got to be a more elegant way (this is ruby, after all).

I've also got something working with grep, but it seems hackish since I'm using an array and just grabbing the first element:

input="FOO: 1 BAR: 2"
foo, bar = input.grep(/FOO: (\d+) BAR: (\d+)/){[$1,$2]}[0]
p foo
p bar

I've tried searching online and browsing the ruby docs, but haven't been able to figure anything better out.

robustus
  • 3,626
  • 1
  • 26
  • 24
zje
  • 3,824
  • 4
  • 25
  • 31

3 Answers3

5

Rubys String#match method returns a MatchData object with the method captures to return an Array of captures.

>> string = "FOO: 1 BAR: 2"
=> "FOO: 1 BAR: 2"
>> string.match /FOO: (\d+) BAR: (\d+)/
=> #<MatchData "FOO: 1 BAR: 2" 1:"1" 2:"2">
>> _.captures
=> ["1", "2"]
>> foo, bar = _
=> ["1", "2"]
>> foo
=> "1"
>> bar
=> "2"

To Summarize:

foo, bar = input.match(/FOO: (\d+) BAR: (\d+)/).captures
Lee Jarvis
  • 16,031
  • 4
  • 38
  • 40
  • So something like `foo, bar = input.match(/FOO: (\d+) BAR: (\d+)/).captures`? Definitely more readable – zje Jul 25 '12 at 14:04
  • Nice timing, I literally just altered my original post with the same thing. Yep, that'll do it. – Lee Jarvis Jul 25 '12 at 14:05
1

Either:

foo, bar = string.scan(/[A-Z]+: (\d+)/).flatten

or:

foo, bar = string.match(/FOO: (\d+) BAR: (\d+)/).captures
Michael Kohl
  • 66,324
  • 14
  • 138
  • 158
1

Use scan instead:

input="FOO: 1 BAR: 2"

input.scan(/FOO: (\d+) BAR: (\d+)/) #=> [["1", "2"]]
Kibet Yegon
  • 2,763
  • 2
  • 25
  • 32