What is the proper syntax for a boolean regex method?
Asked Answered
H

11

26

What is the proper syntax for a method that checks a string for a pattern, and returns true or false if the regex matches?

Basic idea:

def has_regex?(string)
    pattern = /something/i
    return string =~ pattern
end

Use case:

if has_regex?("something")
    # woohoo
else
    # nothing found: panic!
end
Hapless answered 7/2, 2010 at 0:12 Comment(4)
Your code works as-is, so I don't really see what you're askingLancelle
Haha, my mistake. I didn't debug my code properly. Thanks for pointing out what should have been obvious.Hapless
There's no reason to define has_regex?, just do if "something" =~ /something/iCompline
I want the pattern to be in its own method because I'm reusing it in multiple places, and I'd like to avoid declaring a global variable.Hapless
E
-3

If you want the put the pattern in a method, you can just do

def has_my_pattern(st)
    st =~ /pattern/
end

Or, perhaps better, put the pattern in a class variable instead?

Exodus answered 8/2, 2010 at 9:15 Comment(1)
This does not return a boolean value. @Ryan's answer is correct.Nudi
M
46

In the question you said:

... method that checks a string for a pattern, and returns true or false if the regex matches

As johannes pointed out String=~ returns nil if the pattern did not match and the position in the string where the matched word stared otherwise. Further he states in Ruby everything except nil and false behave like true. All of this is right.

However, they are not exactly true or false. Therefore, the last step is to coerce the value to be a Boolean. This is achieved by wrapping the result in double bangs returns a true.

def has_regex?(string)
    !!(string =~ /something/i)
end
Mcculloch answered 15/1, 2014 at 1:25 Comment(2)
Or: !(string !~ /something/i)Golanka
For recent versions of Ruby, reference matthew.tuck's answer belowGarnettgarnette
D
15

Your code looks fine, but you could write it even smaller.

The return value of String#=~ behaves this way:

  • nil if the pattern did not match
  • the position in the string where the matched word started

In Ruby everything except nil and false behaves like true in a conditional statement so you can just write

if string=~ pattern
  # do something
else
  # panic
end
Dongola answered 7/2, 2010 at 19:49 Comment(1)
Your answer is right for the provided use case, but does not correctly answer the OP's question (which will matter for people coming here). When assigning the result to an ActiveRecord object for example, this is crucial: Foo.new(admin: (role =~ /admin/)).admin returns false when role is "admin", because =~ returns 0, which is turned into false by Rails. Just sayin'.Merissa
C
14

If you are using Ruby 2.4 or later, there are String#match?(regex) and Regexp#match?(string) methods that return booleans without the conversion shenanigans (where they are needed, though they usually aren't), and have improved performance to boot.

https://ruby-doc.org/core-2.4.0/Regexp.html#method-i-match-3F

https://blog.cognitohq.com/new-features-in-ruby-2-4/

Communize answered 14/7, 2017 at 5:33 Comment(0)
T
11

To make it return true/false switch the position of pattern and string and use case equality ===

def has_regex?(string)
    pattern = /something/i
    return pattern === string
end

I absolutely needed it to return true boolean value and digged around. It is actually documented in regexp class http://www.ruby-doc.org/core-2.1.3/Regexp.html#method-i-3D-3D-3D

Torsi answered 24/10, 2014 at 9:7 Comment(1)
This is the best solution, however, it should be noted that when str is neither a String nor a Symbol, regex === str returns false while other solutions posted here that uses =~ raises a TypeError.Tedmann
S
10

For Ruby >= 2.4 or Rails, you can do:

 regexp.match?(string)
Scaremonger answered 24/1, 2018 at 23:13 Comment(0)
T
2

Adding this to the String class makes it pretty simple to use:

   class String
      def match?(regex)
          !!self.match(regex)
      end
   end

I added it to Rails initializer (RAILS_ROOT/config/initializers) and you can call directly from the string:

"Something special!".match?(/something/i) #=> true 
"Somethin' special!".match?(/something/i) #=> false 
Twombly answered 22/5, 2014 at 15:58 Comment(0)
K
1

For anyone's future reference, double bangs are frowned upon from bbatsov's ruby style guide. Instead of using a double bang, just check if the value isn't nil. If the value isn't nil, it exists.

Instead of doing this:

def has_regex?(string)
  !!(string =~ /something/i)
end

You can always do this:

def has_regex?(string)
  !(string =~ /something/i).nil?
end
Krumm answered 9/10, 2015 at 7:59 Comment(3)
Maybe (string =~ /something/i).present? so you don't have to invert it?Mccrary
I prefer (string =~ /something/i) != nil because I find it more readable.Golanka
Note that present? is an ActiveSupport method (i.e. part of Rails) and isn't available if you're just using regular Ruby.Bonaparte
K
1

I do not have enough reputation to comment, so I will answer instead.

Use of ===, as suggested by viljar, is advised against in the Ruby Style Guide and will cause Rubocop complaints (under default rules).

I find the most readable way to be:

def match?(string)
  !(string =~ /something/i).nil?
end
Knighterrantry answered 13/7, 2020 at 11:11 Comment(0)
P
0

As I wanted this to work generally, and not just for any specific project, I do not want to modify the environment at all.

I was able to get it to work by simply using the return value from the normal match method as a conditional. Tested both the positive and negative case on this sample string:

irb(main):014:0> if "123".match(/.2./); puts "worked"; end
worked
=> nil
irb(main):015:0> if "123".match(/.3./); puts "worked"; end
=> nil
Pasargadae answered 16/3, 2016 at 21:49 Comment(0)
H
-1
def has_regex?(string)
  string.include? pattern
end
Houston answered 2/8 at 9:45 Comment(0)
E
-3

If you want the put the pattern in a method, you can just do

def has_my_pattern(st)
    st =~ /pattern/
end

Or, perhaps better, put the pattern in a class variable instead?

Exodus answered 8/2, 2010 at 9:15 Comment(1)
This does not return a boolean value. @Ryan's answer is correct.Nudi

© 2022 - 2024 — McMap. All rights reserved.