1

I am trying to loop until user inputs an integer. When user inputs a letter, the following code should print "Think of a number":

print "Think of a number "

while user_input = gets.to_i
  if user_input.is_a? Integer
    puts "your number is #{user_input}"
    break
  else
    print "Think of a number "
  end 
end 

I succeeded with my code when user inputs an integer. However when user inputs a string, the to_i method returns 0, and does not execute the else statement because it is a number.

3

4 Answers 4

4

The main issue with your code is String#to_i method is omnivorous.

"0".to_i #⇒ 0
"0.1".to_i #⇒ 0
"foo".to_i #⇒ 0

That said, user_input in your code is always integer.

What you probably want is to accept digits only (and maybe a leading minus for negatives.) The only concise way to accept a subset of characters is a regular expression.

# chomp to strip out trailing carriage return
user_input = gets.chomp 

if user_input =~ /\A-?\d+\z/
  ...

The regular expression above means nothing save for digits with optional leading minus.


Or, even better (credits to @Stefan)

if gets =~ /\A-?\d+\Z/
Sign up to request clarification or add additional context in comments.

4 Comments

Don't always use the positive form for matching. Use !user_input.match?(/\D/).
This is old-school way. Nowadays, you can use Integer method.
@sawa yes, Integer(exception: false) but Ruby 2.6 is not yet everywhere. Also, /\D/ would hardly allow negatives.
There's also \Z (uppercase) which allows you to omit chomp.
2

If you only want to accept postive digits, you can use a range:

user_input = gets.chomp 
if ('0'..'9').cover? user_input

Comments

0

let check below one used Integer(gets.chomp) rescue ''

print "Think of a number "

while user_input = Integer(gets.chomp) rescue ''
  if user_input.is_a? Integer
    puts "your number is #{user_input}"
    break
  else
    print "Think of a number "
  end
end

4 Comments

Integer(get.chomp, exception: false) since Ruby 2.6.
You can omit chomp here, but you probably want to set the base to 10.
@Stefan I am not sure what exactly you mean, because by default the base is 10
to_i has a default base of 10 whereas Integer() has a default base of 0, i.e. it attempts to determine the base from the input: Integer('0100') #=> 64
-1

I came across a similar problem. I ended up doing this:

if user_input.strip == user_input.to_i.to_s
  # More code here!
end

Testing for float would be:

if user_input.strip == user_input.to_f.to_s
  # More code here!
end

Solved my issue. See if it helps.

4 Comments

The latter would eliminate integers though.
Exactly. It checks only for floats. If one needs both, they can be ored.
Technically 1 is somewhat float since 1 == 1.0 #⇒ true.
Also it won’t work on absolutely legit 01 for integers and 1.00 for floats.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.