tags:

views:

148

answers:

5
match, text, number = *"foobar 123".match(/([A-z]*) ([0-9]*)/)

I know this is doing some kind of regular expression match but what role does the splat play here and is there a way to do this without the splat so it's less confusing?

A: 

String.match returns a MatchData object, which contains all the matches of the regular expression. The splat operator splits this object and returns all the matches separately.

If you just run

"foobar 123".match(/([A-z]*) ([0-9]*)/)

in irb, you can see the MatchData object, with the matches collected.

tobiasvl
+4  A: 

The splat is decomposing the regex match results (a MatchData with three groups: the whole pattern, the letters, and the numbers) into three variables. So we end up with:

match = "foobar 123"
text = "foobar"
number = "123"

Without the splat, there'd only be the one result (the MatchData) so Ruby wouldn't know how to assign it to the three separate variables.

Jon Skeet
+2  A: 

There's a good explanation in the documentation for MatchData:

Because to_a is called when expanding *variable, there‘s a useful assignment shortcut for extracting matched fields. This is slightly slower than accessing the fields directly (as an intermediate array is generated).

   all,f1,f2,f3 = *(/(.)(.)(\d+)(\d)/.match("THX1138."))
   all   #=> "HX1138"
   f1    #=> "H"
   f2    #=> "X"
   f3    #=> "113"
Pesto
A: 

MatchData is a special variable, for all intents and purposes an array (kind of) so you can in fact do this as well:

match, text, number = "foobar 123".match(/([A-z]*) ([0-9]*)/)[0..2]

Learn more about the special variable MatchData

Julian
It's a class, not a variable (well technically it's a constant pointing to a class, but so are String, Array etc) and there's nothing special about it. You can call `[]` on a MatchData instance because it defines `[]` and you can use the splat operator on it because it defines `to_a`.
sepp2k
+2  A: 

is there a way to do this without the splat so it's less confusing?

Since a,b = [c,d] is the same as a,b = *[c,d] and splat calls to_a on its operand when it's not an array you could simply call to_a explicitly and not need the splat:

match, text, number = "foobar 123".match(/([A-z]*) ([0-9]*)/).to_a

Don't know whether that's less confusing, but it's splatless.

sepp2k