Difference between gets.chomp.to_i and gets.chomp in Ruby - ruby

What is the difference between gets.chomp.to_i and gets.chomp in Ruby? What does it do and how does it work?

gets asks a user for some input and returns it exactly as it was entered. Notice that the returned value is a string and contains a newline at the end (since the user pressed the Enter key to submit their response):
> gets
> 1 # user input
=> "1\n"
Adding chomp removes the newline (technically, the record separator) from the input. Notice that "1" is now missing the newline at the end, but is still a string:
> gets.chomp
> 1 # user input
=> "1"
Adding to_i converts the input string into an integer. Notice that the return value is now an integer:
> gets.chomp.to_i
> 1 # user input
=> 1
Performing conversion with .to_i only make sense for integer inputs, as other string values will return 0:
> gets.chomp.to_i
> foo # user input
=> 0

gets is used in scripts to retrieve user input. .chomp is used to remove newlines and carriage returns. See here.
gets.chomp does return a string -> to_i converts the string to an integer.

Related

Loop until answer is a string

I'm trying to loop this question until the user's input is a string value:
Question: What is your name?
I don't want the user to just press enter and leave the name blank.
I don't want the user's input to be numeric/numbers.
Please see my code below:
name1 = gets.chomp.to_s
loop do
print "Please enter your name "
name1 = gets.chomp.to_s
if name1.empty?
puts "No input."
else name1.to_i
puts "Illegal character ':'"
end
end
With this code, I can't proceed to the next question even if I input a string value. Please help.
Your code has several issues:
Your input and output is out of order. You gather input before prompting and that input (from your first line) is never used:
name1 = gets.chomp.to_s # <- Ruby is waiting for input
loop do
print "Please enter your name " # <- user is prompted to enter name
name1 = gets.chomp.to_s # <- previous input is overwritten
# ...
end
The first line should probably be deleted.
gets might return nil, but chomp always returns a string. Calling to_s afterwards is therefore superfluous.
Your if-else construct is actually:
if name1.empty?
puts "No input."
else
name1.to_i
puts "Illegal character ':'"
end
So whenever the input is not empty?, you convert it to an integer (discarding the result) and print an error message. You probably want an elsif instead (/.../ is a regexp and \d matches a digit):
if name1.empty?
puts 'No input.'
elsif name1.match? /\d/
puts 'Digits not allowed.'
end
You could also use a case expression:
case name1
when ''
puts 'No input.'
when /\d/
puts 'Digits not allowed.'
end
You never break out of your loop. The code keeps looping even if no error was found. This can be fixed by adding a break statement in an else branch (to either if or case):
# ...
else
break
end
gets.chomp will always return a string, and as such there is no need to call to_s on the method.
If you don't want the user to be able to input any integers, you could use the following for a clean solution:
name.count("0-9") > 0
If this returns true, then you know that the user's input contains at least one number.

How to accept a user input from the console but not use gets.chomp

As I understand it, the way to accept user input is
puts "Can you guess what number the computer is thinking of?"
userguess = gets.chomp
gets.chomp is a string method and so if the user enters the number 5, userguess stores the value "5" as string. I would then have to do userguess.to_i! to convert this to an int. However, I would not like to do this. I want to accept the user input either as a string or an int and then have the program do something like:
if #guess.is_a?(Integer) == true
puts "I got your number. Let me get back to you."
# do something
elsif #guess.is_a?(Integer) == false
puts "That's not a number. You MUST enter a number! Try again"
# Ask the user to guess again.
else
#something else
end
I don't want to accept the user input explicitly as a string because I want to check if it is a string or an int later on in the program. How would I do this?
That is impossible. All user input from the terminal are a string. If it were possible, how would you think a user can input a number 5 as opposed to a string "5"?
No, that is not possible.
But you can define a little function to check whether that string can be an integer or not:
def is_i?(s)
s.to_i.to_s == s
end
Be aware that string with spaces will not be an integer in this case:
is_i? '123' # true
is_i? '123 ' # false
is_i? ' 123' # false
is_i? '12 123' # false
To handle second and third example you can strip your user input.
Your code will look like:
guess = gets.chomp.strip
if is_i? guess
puts 'is integer'
else
puts 'is not an integer'
end
To check if a string contains valid integer (or float, etc.) you could use this approach:
def coerce(string)
Integer(string) rescue Float(string) rescue string
end
coerce('115').class # Fixnum
coerce('115.12').class # Float
coerce('115.aa').class # String
Also check out highline gem, it provides lots of helpful functionality when it comes to cli.
You don't understand how a keyboard device and the console input work.
ALL input typed on the keyboard and read via gets or anything else, is always a String. You can not get anything else.
We use gets.chomp to remove the trailing newline that is entered when the user presses Return or Enter. For instance, a bare gets will return a line-end if I enter nothing else:
gets #=> "\n"
Adding additional characters results in those characters, plus the terminating line-end:
gets #=> "foo\n"
We use chomp to remove that trailing line-end. Repeating the same inputs and using chomp:
gets.chomp #=> ""
gets.chomp #=> "foo"
Ruby makes it easy to tell if what was input can be cleanly converted to an integer. Simply use Integer(). Here is some output from an IRB session:
>> Integer('1') #=> 1
>> Integer('123') #=> 123
>> Integer('foo')
ArgumentError: invalid value for Integer(): "foo"
from (irb):14:in `Integer'
from (irb):14
from /usr/local/bin/irb:12:in `<main>'
>> Integer('1a')
ArgumentError: invalid value for Integer(): "1a"
from (irb):15:in `Integer'
from (irb):15
from /usr/local/bin/irb:12:in `<main>'
Using a rescue makes it easy to handle the exception:
begin
Integer('1')
rescue ArgumentError
puts 'not a number'
end #=> 1
Or:
begin
Integer('a')
rescue ArgumentError
'not a number'
end #=> "not a number"

Whats wrong with the modulus operator in this Ruby code?

def factors_to_three (n)
puts n
if n % 3 == 0
puts "Your number is divisible by 3"
else
puts "Your Number is NOT divisible by 3"
end
end
puts "Enter the number to check if its divisible by 3"
number = gets.chomp
factors_to_three(number)
No matter what number I input, my program always outputs Your Number is NOT divisible by 3, even when clearly is.
n is not an integer. gets() returns a string and chomp removes the newline, but the data is still a string.
"6" % 3 != 0
6 % 3 == 0
You need to convert your incoming data to an integer representation.
Your result will always be false because gets.chomp returns a String:
number = gets.to_i
The above code will work but you must always type an integer. There are better ways to manage checking to see if the input is valid.
So you could check first like this:
number = gets
factors_to_three(number.to_i) if number.is_a?(Integer)
When text is read using gets, it is read in as a string. So in your code, number is actually not a number, but a string. Because of this, the "modulus" operator is in fact not the modulus operator, but the format operator on String, String#%:
Format—Uses str as a format specification, and returns the result of applying it to arg. If the
format specification contains more than one substitution, then arg
must be an Array or Hash containing the values to be substituted. See
Kernel::sprintf for details of the format string.
"%05d" % 123 #=> "00123"
"%-5s: %08x" % [ "ID", self.object_id ] #=> "ID : 200e14d6"
"foo = %{foo}" % { :foo => 'bar' } #=> "foo = bar"
As you can see, this method returns a string, which does not equal zero. Therefore, this program will always say that the number is not divisible by 3, even when it is.
You can fix this by calling to_i on the input returned from get:
number = gets.chomp.to_i

Ruby: Get last character from user input

So I'm trying to find the last character from user input in Ruby.
I've tried the following-
print "Enter in a string: "
user_input = gets
end_char = user_input[-1,1]
puts "#{end_char} is the last char!"
But it returns
" is the last char!".
I've tried
end_char = "test"[-1,1]
and that works as it should (returns t). But its not working when I use user input as the string instead of just typing in a string itself. Help?
So when you say "Enter in a string" and you type "foo", what's the last thing you do? Well you hit enter obviously! So what you actually capture is "foo\n".
Calling user_input[-1,1] actually gives back the \n return symbol which just prints a break return in the output.
print "Enter in a string: "
user_input = gets.chomp
end_char = user_input[-1,1]
puts "#{end_char} is the last char!"
the #chomp method actually removes the return character from the input.
Now when I run it:
stacko % ruby puts.rb
Enter in a string: hi Lupo90
0 is the last char!
Consider this IRB session:
I'll enter "foo":
irb(main):001:0> user_input = gets
foo
"foo\n"
I entered "foo", and to terminate the input I had to press Return (or Enter depending on the OS and keyboard), which is the "\n" (or "\r\n") line-ending, depending on whether your OS is *nix or Windows.
Looking at what I entered:
irb(main):002:0> user_input[-1]
"\n"
Here's what is output. Notice that the single-quotes are on separate lines because a "\n" is a new-line character:
irb(main):003:0> puts "'\n'"
'
'
nil
(The trailing nil is the result of puts and isn't important for this example.)
So, gets returned everything entered, including the trailing new-line. Let's fix that:
irb(main):004:0> user_input = gets.chomp
foo
"foo"
irb(main):005:0> user_input[-1]
"o"
irb(main):006:0> puts '"%s" is the last char' % [user_input[-1]]
"o" is the last char
chomp is used to strip trailing line-end from the end of a string:
irb(main):010:0> "foo\n".chomp
"foo"
irb(main):011:0> "foo\r\n".chomp
"foo"
This is a really common question on Stack Overflow. Perhaps searching for it would have helped?

Ruby sentinel loop not working as expected (Seven Languages In Seven Weeks)

Just started working through the Ruby chapter in Mr. Tate's "Seven Language in Seven Weeks".
For the bonus question in Day 1, I am to generate a "random" number, read a user's guess from the input, and compare the guess to my "random" number, then prompt the user to continue guessing with the begin loop. However, the loop seems to terminate regardless of what the value of the string the user inputs.
# file : day1_bonus.rb
# Seven Languages In Seven Weeks
#
# Guess a random number!
again = "y"
begin
print "Enter a number between 0 and 9: "
number = gets.to_i
randNum = rand(10)
if number == randNum
puts 'You guessed correctly!'
else
puts 'You guessed incorrectly.'
end
print "Play again? (y/n): "
again = gets
again.chomp # remove carriage return
end while again == "y"
Output:
Enter a number between 0 and 9: 3
You guessed incorrectly.
Play again? (y/n): y
nil
There are two versions of chomp. The regular chomp and bang chomp!. The difference being: regular returns modified string (and leaves source alone) while the bang version modifies original string in-place.
So, in your code you chomp the carriage return and throw away this work. Either do this
again = again.chomp
or this
again.chomp!

Resources