Turbo
Turbo

Reputation: 29

And/Or operator is ruby?

I have a quick question on Ruby syntax: I am trying to write a program where it takes a string and replaces substrings with a different substring IF it contains the initial substring. Here is my code:

print "Thtring, pleathe!"

user_input = gets.chomp

if user_input.include? "s" || "S" || "cy" || "ce" || "ci"

    user_input.gsub!(/s/, "th")
    user_input.gsub!(/S/, "Th") 
    user_input.gsub!(/cy/, "th") 
    user_input.gsub!(/ce/, "th") 
    user_input.gsub!(/ci/, "th") 
else

    puts "No 's' found!"
end

puts "#{user_input}!" 

This works fine until I have a sentence that doesn't contain "s" in it. Then it just prints the original string with no changes. Is there a logical operator that means AND/OR in Ruby? To replace all the ORs (||) with. And if there isn't, how would I rewrite this to make it work?

Upvotes: 1

Views: 114

Answers (5)

the Tin Man
the Tin Man

Reputation: 160551

There's some seemingly little-known magic that gsub can do using a regexp pattern and a hash.

Starting with a hash of the target strings to be found and their replacements:

substitutions = {
  's' => "th",
  'S' => "Th",
  'cy' => "th",
  'ce' => "th",
  'ci' => "th",
}

We can build a regular expression based on the keys (target strings):

substitution_pattern = Regexp.union(substitutions.keys) # => /s|S|cy|ce|ci/

And pass the pattern and the hash to gsub:

'String please!'.gsub(substitution_pattern, substitutions) # => "Thtring pleathe!"

Here are the individual tests:

's'.gsub(substitution_pattern, substitutions) # => "th"
'S'.gsub(substitution_pattern, substitutions) # => "Th"
'cy'.gsub(substitution_pattern, substitutions) # => "th"
'ce'.gsub(substitution_pattern, substitutions) # => "th"
'ci'.gsub(substitution_pattern, substitutions) # => "th"

The pattern being built by Regexp.union isn't especially good, because all it really does is join('|'). We can easily create a smarter pattern:

substitution_pattern = /[Ss]|c[eiy]/
'String please!'.gsub(substitution_pattern, substitutions) # => "Thtring pleathe!"

There are several answers on Stack Overflow where I use a Perl module called Regexp::Assemble to generate very complex patterns for this purpose. Check out these Regexp::Assemble answers for more information. In particular, "Is there an efficient way to perform hundreds of text substitutions in Ruby?" will show you all you need to know to do this.

Upvotes: 1

Stefan Dorunga
Stefan Dorunga

Reputation: 679

An easy way of doing it is to just use a regexp. You could do

if user_input.match(/(s|S|cy|ce|ci)/)
  ...
else
  ...
end

There are also, as always, other options such as in Milan Vladimirovic's answer:

if user_input =~ /(s|S|cy|ce|ci)/

as well as Tin Man's suggestion

if user_input[/(s|S|cy|ce|ci)/]

Use whichever you prefer since they are for this scenario functionally equivalent. The other thing is you could just run the gsubs anyway since they won't cahnge anything that isn't there, unless you really want to output the "No 's' found!"

Upvotes: 0

Milan Köpke
Milan Köpke

Reputation: 1133

I guess you have a problem with operator binding priorities. Wrapping the ORs (||) in brackets (include?('s') || include?('S')) should do the trick and make your code work.

You could also write it as a regular expression:

if user_input =~ /s|S|cy|ce|ci/
  user_input.gsub!(/s/, "th")
  user_input.gsub!(/S/, "Th") 
  user_input.gsub!(/cy/, "th") 
  user_input.gsub!(/ce/, "th") 
  user_input.gsub!(/ci/, "th")
else
  puts "No 's' found!"
end

Upvotes: 0

Weetu
Weetu

Reputation: 1773

What you're doing now is effectively

if user_input.include?("s") || "S" || "cy" || "ce" || "ci"

(Note the added parentheses.) Also, you can't do something like that in Ruby - the || operator only works for boolean expressions.

You have two alternatives:

if user_input.include?("s") || user_input.include?("S") || user_input.include?("cy") || user_input.include?("ce") || user_input.include?("ci")

or the much neater

if user_input =~ /s|S|cy|ce|ci/

Upvotes: 3

spickermann
spickermann

Reputation: 106882

It is just:

print "Thtring, pleathe!"
user_input = gets.chomp

puts "No 's' found!" unless user_input.gsub!(/s|S|cy|ce|ci/, 'th')

puts "#{user_input}!"

What works, because gsub! returns nil if nothing is replaced.

Upvotes: 2

Related Questions