How to display modified string? - ruby

I am creating a Daffy Duck speech converter (Very simple. Straight from CodeCademy) and I am having an issue with displaying the modified entry from the user.
Code:
puts "What would you like to convert to Daffy Duck language?"
user_input = gets.chomp
user_input.downcase!
if user_input.include? "s"
user_input.gsub!(/s/, "th")
print #{user_input}
else puts "I couldn't find any 's' in your entry. Please try again."
end
It will change any 's' in your entry to a 'th', therefore, making it sound like a Daffy Duck once read aloud. When I enter it into the interpreter, it will not display the modified string. It will just display the original entry by the user.
EDIT:
Thanks to the users below, the code is fixed, and I added a notice to the user with converted text. Thanks guys!

A # outside a string starts a comment, so #{user_input} is ignored, i.e.
print #{user_input}
is equivalent to
print
You might wonder why a single print outputs the original input. This is because without arguments print will print $_. That's a global variable which is set by gets:
user_input = gets.chomp # assume we enter "foo"
user_input #=> "foo"
$_ #=> "foo\n"
Everything works as expected if you pass a string literal:
print "#{user_input}"
or simply
print user_input
Note that gsub! returns nil if no substitutions were performed, so you can actually use it in your if statement:
if user_input.gsub!(/s/, "th")
print user_input
else
puts "I couldn't find any 's' in your entry. Please try again."
end

You just need to add double quotes around the string interpolation. Otherwise your code was just returning the input.
puts "What would you like to convert to Daffy Duck language?"
user_input = gets.chomp
user_input.downcase!
if user_input.include? "s"
user_input.gsub!(/s/, "th")
print "#{user_input}"
else
puts "I couldn't find any 's' in your entry. Please try again."
end

You don't even need interpolation, actually. print user_input works. Notice how StackOverflow was even syntax highlighting your code as a comment. :)

Related

What is wrong here in this Ruby Program?

I want in brief to run a program to check if the user input is empty to let him reinsert the needed data and in case there is "s" in the string to be substituted with another letter
print "Please enter a string: "
user_input = gets.chomp.downcase!
if user_input.empty?
print "Please enter a vaild string... "
user_input = gets.chomp.downcase!
elsif
user_input.include? "s"
user_input.gsub!(/s/, "th")
else
puts "There are no 's's in your string. #{user_input}"
end
puts "Your new thtring is #{user_input}."
The problem is with this line
user_input = gets.chomp.downcase!
according to the docs
Downcases the contents of str, returning nil if no changes were made.
So if the user inputs a string with only lowercase letters, nil is returned.
Your function works if a user enters FOO, then it works fine.
You're better off using downcase instead of downcase!. downcase always return the string itself.
As I understand you need get valid user input (with s)
Now you are only using if and this does not guarantee that user input will be valid
You can refactor to something like this
puts "Please enter a string with s:"
thtring = ""
loop do
user_input = gets.chomp
next puts "Please enter some string..." if user_input.empty?
thtring = user_input.downcase
next puts "There are no 's's in your string" unless thtring.include?("s")
break thtring.gsub!(/s/, "th")
end
puts "Your new thtring is #{thtring}."

How do I request user input until user enters valid input in ruby?

This is a problem where they have asked me to add an additional if statement to re-prompt the user for input if they don't enter anything.
I have tried to use the while loop, but still can't solve the problem
print "please enter a sentence with a letter s"
while user_input = gets.chomp.downcase!
case user_input
when user_input.include? "s"
user_input.gsub(/s/,"th")
print "Daffy Duck says #{user_input}"
break
else
print "please enter a sentence with a letter s"
end
I expect "please enter a sentence with a letter s" to loop until the user enters the letter "s"
My understanding is that the user enters sentences until one contains an "s" or an "S", at which time a certain action is taken and the program terminates.
Let's go through what you have.
print "Please enter a sentence with a letter s"
I think you want puts, which adds a newline character, rather than print, which does not.
while user_input = gets.chomp.downcase!
Suppose the user enters "Cat" (even though it's not a sentence), then presses the Enter key, then
str0 = gets
#=> "Cat\n"
str1 = str0.chomp
#=> "Cat"
user_input = str1.downcase!
#=> "cat"
str1
#=> "cat"
user_input
#=> "cat"
so we have
while "cat"
As "cat" is neither false nor nil (the only logical false objects), this is the same as
while true
so execution moves to the first statement within the while loop. Suppose instead the user entered "cat" and pressed the Enter key. Then
str0 = gets
#=> "cat\n"
str1 = str0.chomp
#=> "cat"
user_input = str1.downcase!
#=> nil
str1
#=> "cat"
user_input
#=> nil
so the program would not enter the while loop! How, you ask, can "cat".downcase return nil? Look at the doc for String#downcase!. It shows that nil is returned if there were no characters to downcase. Ruby has many methods that do the same: if the receiver is not altered nil is returned. (Don't get sidetracked with "why" at this point of your education.) For the present you are advised to avoid using bang methods (ending with an "!").
Similarly, if the user didn't enter anything and pressed enter,
str1 = "\n".chomp
#=> "" (an empty string)
user_input = str1.downcase
#=> nil
"".downcase! returns nil for the same reason that "cat".downcase! does.
I think what you what here is the following.
user_input = gets.chomp
while !user_input.match?(/s/i)
/s/i is a regular expression used to determine if the string contains an "s" or an "S". i in /i is a case-indifference modifier. (One could instead write while user_input !~ /s/i.)
The first statement within the while loop is
case user_input
When case has an argument (here user_input) the when statements contain arguments that are possible values of the case argument, for example
case user_input
when "call me silly!"
puts "You are silly"
when...
You are not doing that here, so you want case on a line by itself:
case
when user_input == ...
...
end
Here, however, there is no need for a case statement or "if/elsif/else/end" construct within the loop because we have already determined that user_input does not contain an "s". All we need in the loop is this:
while !user_input.match?(/s/i)
puts "Please enter a sentence with a letter s"
user_input = gets.chomp
end
After the loop is terminated user_input is a string that contains an "s". We therefore need only perform the following.
puts "Daffy Duck says #{user_input}"
#=> "Quack, quack, quackity-quack, sir"
Note that your statement
user_input.gsub(/s/, "s")
substitutes each "s" with an "s". :-) Nor is there a need for the break keyword.
Putting all this together, you could write:
puts "Please enter a sentence with a letter s"
user_input = gets.chomp
while !user_input.match?(/s/i)
puts "Please enter a sentence with a letter s"
user_input = gets.chomp
end
puts "Daffy Duck says #{user_input}"
You thought I was finished. Not so fast!
Firstly, many Ruby coders try to avoid negations such as while !user_input.match?(/s/i) (though it is purely a matter of taste). You could instead write that line
until user_input.match?(/s/i)
A more significant problem is the replication of code. You can improve upon that by using Kernel#loop and the keyword break instead of while or until.
loop do
puts "Please enter a sentence with a letter s"
user_input = gets.chomp
if user_input.match?(/s/i)
puts "Daffy Duck says #{user_input}"
break
end
end
If, however, we wrote
loop do
puts "Please enter a sentence with a letter s"
user_input = gets.chomp
break if user_input.match?(/s/i)
end
puts "Daffy Duck says #{user_input}"
The last line would raise the exception
NameError (undefined local variable or method `user_input' for main:Object)
because the variable user_input is only defined within the loop.
I generally use loop and break in preference to while or until.
Is your problem a program not working?
What do you want to do the following?
please enter a sentence with a letter s: a
please enter a sentence with a letter s: s
Daffy Duck says: s
in this case,
print "please enter a sentence with a letter s: "
while user_input = gets
user_input.chomp.downcase!
if user_input.include? "s"
user_input.gsub(/s/,"s")
print "Daffy Duck says: #{user_input}"
return
else
print "please enter a sentence with a letter s: "
end
end
The i after /s/ is case-insensitive search.
If the string has an s and we remove it, the
original will not match
puts "please enter a sentence with a letter s"
while user_input = gets
user_input = user_input.chomp
if user_input != user_input.gsub(/s/i,"")
puts "Daffy Duck says: #{user_input}"
break
else
puts "please enter a sentence with a letter s"
end
end
The match location will be a zero-based integer index if found
or nil if no match
puts "please enter another sentence with a letter s"
while user_input = gets
user_input = user_input.chomp
match_location = user_input =~ /s/i
if match_location.nil?
puts "please enter a sentence with a letter s"
else
puts "Daffy Duck says: #{user_input}"
break
end
end

Code to see if user input was filled

I want to check if a field was filled in. I have an imcompleted code:
print "What is your name?"
user_input = gets.chomp.upcase
if user_input = ??
print "Nice to meet you user_input!"
else
puts "Please enter your name."
end
How do I complete the code to do that?
Under the premise that you would like to:
Print out a message: "What is your name?"
Have the user enter their name and store it in the user_input variable(with gets.chomp)
Output either "Nice to meet you << user name >>" or "Please enter your name" depending on whether the input matches certain criteria
...we have a few changes to make.
The first being the condition of checking to make sure the input isn't blank and the second being seeing if the input matches a certain value.
First, let's check to see if the input is empty before continuing. We can use String#empty to make sure the string has at least one character (including whitespace):
print "What is your name?"
user_input = gets.chomp.upcase
# Check to make sure the input isn't empty
if !user_input.empty?
print "Nice to meet you user_input!"
else
puts "Please enter your name."
end
Then, we can check to see if the input matches certain criteria. Unfortunately, your question doesn't specify what these criteria are, so as other users are suggesting you can use regex to see if it matches a particular pattern, or just use a hard coded string to compare:
print "What is your name?"
user_input = gets.chomp.upcase
# After making sure the input is empty, check to make sure it matches the string "Bob"
if !user_input.empty? && user.input == "Bob"
print "Nice to meet you user_input!"
else
puts "Please enter your name."
end
Lastly, there is one bug in the code. The output once a user's input has been validated will always be "Nice to meet you user_input", even when the user_input variable is another value. This is because we aren't using String Interpolation properly:
print "What is your name?"
user_input = gets.chomp.upcase
if !user_input.empty? && user.input == "Bob"
# When using string interpolation, surround the variable you'd like to print with #{}
print "Nice to meet you #{user_input}!"
else
puts "Please enter your name."
end
As other users have stated, you should consider fine tuning the requirements of your problem a bit more. You can add a lot of detail and experimentation to this simple example!
There's a lot of context missing from the question, but there are a couple of things that may be helpful to you.
Basic check if it's nil or empty:
if user_input.nil? || user_input.empty?
# Ask the user to try again
end
Check if it matches a pattern you specify using a Regex (see https://ruby-doc.org/core-2.1.1/Regexp.html). For example:
if user_input =~ /^[[:upper:]][[:lower:]]+/
# One uppercase character, followed by at least one lowercase
end
The second option has far more possibilities, but again it depends on your needs.
if user_input.blank?
puts "please enter your name"
else
puts "Nice to met you"
end

Ruby bang strange behaviour

I wrote the following code:
print "Please enter a string"
user_input = gets.chomp
user_input.downcase!
if user_input.include? "s"
print "Changing #{user_input} to #{user_input.gsub!(/s/,'th')}"
else
print "No s in the string"
end
and I found that user_input and user_input.gsub!(/s/,'th') contain the same value. This happens because of the bang operation on gsub and because they are part of the same string.
Splitting the print in two lines changes the behavior:
print "Changing #{user_input} to "
print "#{user_input.gsub!(/s/,'th')}"
I wonder if this is a bug.
It's a feature, not a bug.
String interpolation (the "#{}" operator) works by finding all the dynamic parts, evaluating them and then glueing static and dynamic parts together into one string. Since all dynamic parts are evaluated prior to concatenation, gsub! mutates the object which user_input points to. So the first appearance of inner_page in that string will see the updated value.
Solution: don't use dangerous gsub!, use safe gsub.
You can observe here, how it really happens (VM instructions). This will probably be Chinese to you at the moment, but in a few years you'll understand. :)
code = <<-RUBY
user_input = 'blah'
print "Changing \#{user_input} to \#{user_input.gsub!(/s/,'th')}"
RUBY
puts RubyVM::InstructionSequence.new(code).disasm

gets.chomp without moving to a new line

I understand about the \n that's automatically at the end of puts and gets, and how to deal with those, but is there a way to keep the display point (the 'cursor position', if you will) from moving to a new line after hitting enter for input with gets ?
e.g.
print 'Hello, my name is '
a = gets.chomp
print ', what's your name?'
would end up looking like
Hello, my name is Jeremiah, what's your name?
You can do this by using the (very poorly documented) getch:
require 'io/console'
require 'io/wait'
loop do
chars = STDIN.getch
chars << STDIN.getch while STDIN.ready? # Process multi-char paste
break if ["\r", "\n", "\r\n"].include?(chars)
STDOUT.print chars
end
References:
http://ruby-doc.org/stdlib-2.1.0/libdoc/io/console/rdoc/IO.html#method-i-getch
http://ruby-doc.org/stdlib-2.1.0/libdoc/io/wait/rdoc/IO.html#method-i-ready-3F
Related follow-up question:
enter & IOError: byte oriented read for character buffered IO
Perhaps I'm missing something, but 'gets.chomp' works just fine does it not? To do what you want, you have to escape the apostrophe or use double-quotes, and you need to include what the user enters in the string that gets printed:
print 'Hello, my name is '
a = gets.chomp
print "#{a}, what's your name?"
# => Hello, my name is Jeremiah, what's your name?
Works for me. (Edit: Works in TextMate, not Terminal)
Otherwise, you could just do something like this, but I realise it's not quite what you were asking for:
puts "Enter name"
a = gets.chomp
puts "Hello, my name is #{a}, what's your name?"

Resources