12

I am using Ruby 1.9.3. I was playing with some patterns and found something interesting:

Example 1:

irb(main):001:0> /hay/ =~  'haystack'
=> 0
irb(main):003:0> /st/ =~ 'haystack'
=> 3

Example 2:

irb(main):002:0> /hay/.match('haystack')
=> #<MatchData "hay">
irb(main):004:0> /st/.match('haystack')
=> #<MatchData "st">

=~ returns the first location of its first match, whereas match returns the pattern. Other than that, is there any difference between =~ and match()?

Execution time difference (As per @Casper)

irb(main):005:0> quickbm(10000000) { "foobar" =~ /foo/ }
Rehearsal ------------------------------------
   8.530000   0.000000   8.530000 (  8.528367)
--------------------------- total: 8.530000sec

       user     system      total        real
   8.450000   0.000000   8.450000 (  8.451939)
=> nil

irb(main):006:0> quickbm(10000000) { "foobar".match(/foo/) }
Rehearsal ------------------------------------
  15.360000   0.000000  15.360000 ( 15.363360)
-------------------------- total: 15.360000sec

       user     system      total        real
  15.240000   0.010000  15.250000 ( 15.250471)
=> nil
DoLoveSky
  • 777
  • 1
  • 6
  • 17
  • 2
    Why down vote i am given? – DoLoveSky Jan 15 '13 at 19:12
  • Both the `operator` and `method` might be doing the same thing, but they are too much different in their functionality - both the post carries too much information and which is really awesome and helpful knowledgeable information for all SO users. In-spite of all these I am getting down vote means really bad for me! I didn't expect that this from the forum. – DoLoveSky Jan 15 '13 at 19:28
  • 1
    I did not downvote you, but I suppose it is because the question as written is moderately nonsensical. You found that there is more than one method that does something similar, but that each returns different results. Why is this interesting? There are many methods in Ruby (and most programming languages) that do similar things but return different results. – Phrogz Jan 15 '13 at 19:29
  • @Phrogz the interesting things comes out from my post to the answers of both. there are the information which has been extracted from the users to SO, due to my post. And the answers are not for me only. it is for all SO followers! – DoLoveSky Jan 15 '13 at 19:33
  • 1
    @Phrogz It would be interesting if the OP were expecting them to do the same thing (as is the case of, e.g., `String#==` and `String#eql?`). The answer could certainly have been found with more research, but it is a fair beginner's question. – Reinstate Monica -- notmaynard Jan 15 '13 at 19:36
  • 1
    And the question is not whether it's interesting (which is subjective), but what the differences are between the methods. – Reinstate Monica -- notmaynard Jan 15 '13 at 19:37
  • @iamnotmaynard `+1` to your comments! – DoLoveSky Jan 15 '13 at 19:55

2 Answers2

10

First make sure you're using the correct operator: =~ is correct, ~= is not.

The operator =~ returns the index of the first match (nil if no match) and stores the MatchData in the global variable $~. Named capture groups are assigned to a hash on $~, and, when the RegExp is a literal on the left side of the operator, are also assigned to local variables with those names.

>> str = "Here is a string"
>> re = /(?<vowel>[aeiou])/    # Contains capture group named "vowel"
>> str =~ re
=> 1
>> $~
=> #<MatchData "e" vowel:"e">
>> $~[:vowel]    # Accessible using symbol...
=> "e"
>> $~["vowel"]    # ...or string
=> "e"
>> /(?<s_word>\ss\w*)/ =~ str
=> 9
>> s_word # This was assigned to a local variable
=> " string"

The method match returns the MatchData itself (again, nil if no match). Named capture groups in this case, on either side of the method call, are assigned to a hash on the returned MatchData.

>> m = str.match re
=> #<MatchData "e" vowel:"e">
>> m[:vowel]
=> "e"

See http://www.ruby-doc.org/core-1.9.3/Regexp.html (as well as the sections on MatchData and String) for more details.

4

When you have a method that does not modify state, all that matters is the return value. So what's the difference between red and blue, besides color? My point is that this is kind of a strange question, one which you seem to already know the answer to. (@sawa set me straight here)

But that said, both methods return nil (a falsy value) when the regex does not match. And, both methods return a truthy value when it does match. =~ returns an integer that represents the first character of the match, and even if that is 0, because 0 is truthy in Ruby. match returns an object with very detailed match data, which is handy when you want lots of info about the match.

=~ is typically used in conditionals, when you only care if something matches:

do_stuff if "foobar" =~ /foo/
do_stuff if "foobar".match(/foo/) # same effect, but probably slower and harder to read

match is typically used when you want details about what was matched:

 name = "name:bob".match(/^name:(\w+)$/)[1]
 puts name #=> 'bob'
Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
  • `+1` to you! great explanation.Lot's of information you have provided to me. thank you very much! – DoLoveSky Jan 15 '13 at 18:53
  • 1
    +1 for the first paragraph alone. (And the rest is good, too. :) – Phrogz Jan 15 '13 at 19:04
  • 1
    All that matters is not only the return value. There is another thing: the speed. It is in principle possible (although it is not actually the case) that `match` does more extensive calculation than `=~` so that may be one factor in deciding which to use. It is not a strange question. I don't think your red vs. blue argument makes any sense. – sawa Jan 15 '13 at 19:34
  • @AlexWayne I would like to say you once again thank you very much for bringing out the most valuable points in your post!! – DoLoveSky Jan 15 '13 at 19:41
  • 3
    Anyone interested I did a very simple benchmark with `=~` vs `match`, and found `=~` to be almost twice as fast as `match`: http://pastie.org/5690542 – Casper Jan 15 '13 at 21:18
  • From Ruby 2.4 (~2016) I believe it is now faster to use `match?` over `=~` in the conditional case: https://bugs.ruby-lang.org/issues/8110 – Barry Sep 26 '22 at 10:05