When extracting data from a string using a regular expression in Ruby, the splat * operator can come in handy.

To show how, let’s parse the string "ios;version=7.0.4" into two variables: one containing the substring "ios" and one containing "7.0.4".

This is one way of doing it:

REGEX  = /^(.*);version=(.*)$/
string = "ios;version=7.0.4"

matches = string.match(REGEX)
os      = matches[1]
version = matches[2]

os         #=> "ios"
version    #=> "7.0.4"

Another way of accomplishing the same thing is to use the splat operator to splat out the returned matches.

REGEX  = /^(.*);version=(.*)$/
string = "ios;version=7.0.4"

_, os, version = *string.match(REGEX)

os         #=> "ios"
version    #=> "7.0.4"

Let’s take a look at how this works behind the scenes.

In the example above, the string stored in the string variable matches the REGEX causing String#match to return a MatchData object.

matches = string.match(REGEX)

matches #=> #<MatchData "ios;version=7.0.4" 1:"ios" 2:"7.0.4">

The MatchData object is then supplied as an argument to the splat operator. The splat operator calls the MatchData#to_a method to get an array representation of the matches.

matches.to_a #=> ["ios;version=7.0.4", "ios", "7.0.4"]

After getting the array, the splat operator explodes it and assigns each of its elements to the corresponding variable on the left side of the assignment.

_, os, version = *["ios;version=7.0.4", "ios", "7.0.4"]

_          #=> "ios;version=7.0.4"
os         #=> "ios"
version    #=> "7.0.4"

Using _ as a variable name might seem odd but it’s completely valid to do so in Ruby; It’s also an idiomatic way of signaling to the reader that the variable’s value isn’t used.

We can use the fact that the splat operator calls to_a on its argument in our own classes like this:

class SplatMe
  def to_a
    [1, 2, 3]
  end
end

splat_me = SplatMe.new
puts *splat_me
#=> 1
#=> 2
#=> 3

But what happens when the string in the example above doesn’t match the REGEX?

REGEX  = /^(.*);version=(.*)$/
string = "does not match"

_, os, version = *string.match(REGEX)

os         #=> nil
version    #=> nil

If the string doesn’t match, String#match returns nil, the splat operator calls NilClass#to_a which always returns an empty array. Splatting an empty array over multiple variables assigns nil to all of them:

a, b, c = *[]

a          #=> nil
b          #=> nil
c          #=> nil