Reputation: 1290
I'm looking for a better way to check, if a string matches multiple regex patterns (or not). This is my approach so far:
class Bob
def hey(remark)
if remark =~ upcase && !(remark =~ downcase) && !(remark =~ numbers)
'Whoa, chill out!'
elsif remark =~ ends_with_questionmark
'Sure.'
elsif (remark =~ numbers) && (remark =~ upcase) && !(remark =~ downcase)
'Whoa, chill out!'
else
'Whatever.'
end
end
def numbers
/[\d]+/
end
def downcase
/[a-z]+/
end
def upcase
/[A-Z]+/
end
def ends_with_questionmark
/[\?]$/
end
end
Upvotes: 1
Views: 883
Reputation: 110695
I find it difficult to comprehend what Bob#hey
is doing. One possibility is to define some appropriately-named helper methods in the String
class:
class String
def contains_a_digit?() !!(self =~ /\d/) end
def contains_no_digits?() !self.contains_a_digit? end
def contains_an_uppercase_char?() !!(self =~ /[A-Z]/) end
def contains_no_lowercase_chars?() self !~ /[a-z]/ end
def ends_with_questionmark?() !!(self =~ /[\?]$/) end
end
Note that (for example) self =~ /\d+/
and self =~ /\d/
are here interchangeable; both return a truthy value if and only if self
contains at least one digit. Incidentally, the receiver, self
, must be explicit here.
Aside to readers unfamiliar with !!
: if truthy
is a variable holding any value other than false
or nil
, !!(truthy) => true
, !!(nil) => false
and !!(false) => false
. In other words, !!
is a trick to convert truthy values to true
and falsy values to false
(which I've used merely to improve readability).
Let's try these methods:
str = 'U2d?' #=> "U2d?"
str.contains_a_digit? #=> true
str.contains_no_digits? #=> false
str.contains_an_uppercase_char? #=> true
str.contains_no_lowercase_chars? #=> false
str.ends_with_questionmark? #=> true
With Ruby 2.1+, if one is disinclined to monkey-patch the String
class, one can use Refinements.
Now the method Bob#hey
can be defined in natural way:
class Bob
def hey(remark)
case
when remark.contains_no_digits? &&
remark.contains_an_uppercase_char? &&
remark.contains_no_lowercase_chars?
'Whoa, chill out! (1st)'
when remark.ends_with_questionmark?
'Sure.'
when remark.contains_a_digit? &&
remark.contains_an_uppercase_char? &&
remark.contains_no_lowercase_chars?
'Whoa, chill out! (2nd)'
else
'Whatever.'
end
end
end
Let's try it.
bob = Bob.new
bob.hey("I PAID IN $US!") #=> "Whoa, chill out! (1st)"
bob.hey("What's that?") #=> "Sure."
bob.hey("I FLEW ON A 777!") #=> "Whoa, chill out! (2nd)"
bob.hey("I give up.") #=> "Whatever."
Upvotes: 3
Reputation: 54992
I think in general more than 2 else
s should be a case
:
def hey remark
case
when remark =~ upcase && !(remark =~ downcase) && !(remark =~ numbers) then 'Whoa, chill out!'
when remark =~ ends_with_questionmark then 'Sure.'
when (remark =~ numbers) && (remark =~ upcase) && !(remark =~ downcase) then 'Whoa, chill out!'
else 'Whatever.'
end
end
But I also think those regexes need work, they probably don't do what you think.
Also you can change !(str =~ /re/)
to str !~ /re/
Upvotes: 1
Reputation: 11591
You code can be rewritten like this
def hey(remark)
if remark =~ /[A-Z]+/
'Whoa, chill out!'
elsif remark =~ /[\?]$/
'Sure.'
else
'Whatever.'
end
end
Upvotes: 0