Regular expression to match number formats - ruby

I'm trying to write a small program that asks a user to input a number and the program will determine if it's a valid number. The user can enter any kind of number (integer, float, scientific notation, etc.).
My question is what regular expression should be used to keep something like "7w" from being matched as a valid number? Also I would like the number 0 to exit the loop and end the program, but as it's written now 0 is matching valid like any other number. Any insight please?
x = 1
while x != 0
puts "Enter a string"
num = gets
if num.match(/\d+/)
puts "Valid"
else
puts "invalid"
end
if num == 0
puts "End of program"
x = num
end
end

You need to execute this script from the command line, not a text editor, as you will be prompt to enter a number.
This is the ultra compact version
def validate(n)
if (Float(n) != nil rescue return :invalid)
return :zero if n.to_f == 0
return :valid
end
end
print "Please enter a number: "
puts "#{num = gets.strip} is #{validate(num)}"
Output:
Please enter a number: 00
00 is zero
Here is a longer version that problably you can extend it to tweak it to your needs.
class String
def numeric?
Float(self) != nil rescue false
end
end
def validate(n)
if n.numeric?
return :zero if n.to_f == 0
return :valid
else
return :invalid
end
end
print "Please enter a number: "
puts "#{num = gets.strip} is #{validate(num)}"
And here is a test for all the possible cases
test_cases = [
"33", #int pos
"+33", #int pos
"-33", #int neg
"1.22", #float pos
"-1.22", #float neg
"10e5", #scientific notation
"X", #STRING not numeric
"", #empty string
"0", #zero
"+0", #zero
"-0", #zero
"0.00000", #zero
"+0.00000", #zero
"-0.00000", #zero
"-999999999999999999999995444444444444444444444444444444444444434567890.99", #big num
"-1.2.3", #version number
" 9 ", #trailing spaces
]
puts "\n** Test cases **"
test_cases.each do |n|
puts "#{n} is #{validate(n)}"
end
Which outputs:
Please enter a number: 12.34
12.34 is valid
** Test cases ** 33 is valid
+33 is valid
-33 is valid
1.22 is valid
-1.22 is valid
10e5 is valid
X is invalid
is invalid
0 is zero
+0 is zero
-0 is zero
0.00000 is zero
+0.00000 is zero
-0.00000 is zero
-999999999999999999999995444444444444444444444444444444444444434567890.99 is valid
-1.2.3 is invalid
9 is valid
Source for the idea of checking if its numeric:
How can I see if the string is numeric?
http://mentalized.net/journal/2011/04/14/ruby_how_to_check_if_a_string_is_numeric/

To start with, you are overcomplicating the loop, secondly, your regular expression needs to be a bit more explicit. Try something like this:
x = 1
while x != 0
puts "Enter a string"
num = gets.chomp
if num == "0"
puts "exiting with 0"
exit 0
elsif num.match(/^[0-9](\.[0-9])?$+/)
puts "Valid"
else
puts "invalid"
end
end
This expression will match any number that contains a digit or a decimal, and will fail to match anything containing letters. If the string entered is exactly 0, the script will exit with status 0.

Related

How do I identify if a character/symbol is a number or not?

I'm doing a simple calculator using Ruby as practice. Everything is fine except how do I identify if a character/symbol I input is a number or not using if-else statement.
For example:
Enter first number: a
Error: Enter correct number
Enter first number: -
Error: Enter correct number
Enter first number: 1
Enter second number:b
Error: Enter correct number
Enter second number: 2
Choose operator (+-*/): *
The product is: 2
This is the code I input first:
print "Enter first number: "
x = gets.to_i
print "Enter second number: "
y = gets.to_i
print "Choose operator (+-*/): "
op = gets.chomp.to_s
I will use if-else statement to identify if the number input is a number or not
If you wish to test if the string represents an integer or float use Kernel#Integer or Kernel#Float with the optional second argument (a hash) having the value of the key :exception equal to false.
For example,
Integer('-123', exception: false)
#=> -123
Integer("0xAa", exception: false)
#=> 170
Integer('12.3', exception: false)
#=> nil,
Integer('12a3', exception: false)
#=> nil
Float('123', exception: false)
#=> 123.0
Float("1.2e3", exception: false)
#=> 1200.0
Float('12a3', exception: false)
#=> nil,
Float('1.2.3', exception: false)
#=> nil
Note
Integer("123\n", exception: false)
#=> 123
shows you don't have to chomp before testing if the string represents an integer (similar with Float).
Some of the examples illustrate a limitation or complication when using a regular expression to test whether a string represents an integer or float.
Create a new String method
irb(main):001:0> class String
irb(main):002:1> def number?
irb(main):003:2> Float(self) != nil rescue false
irb(main):004:2> end
irb(main):005:1> end
irb(main):012:0> x = gets
1
=> 1
irb(main):013:0> x.number?
=> true
irb(main):009:0> x = gets
s
=> "s\n"
irb(main):010:0> x.number?
=> false
This typical way to do this would be to match it with a regexp:
x = gets.chomp
if x.match?(/^\d+$/)
puts "#{x} is a number"
else
puts "#{x} is not a number"
end
This tests if the given string matches the pattern ^\d+$, which means "start of line, one or more digit characters, then end of line". Note that this won't match characters like "," or "." - only a string of the digits 0-9. String#match? will return a boolean indicating if the string matches the given pattern or not.
use this ruby method
.is_a?(Integer)
For example:
input = gets.chomp
input.is_a?(Integer) # => true || false

How to use a boolean for user input validation

Here's part of my code, the first part of the ˚ statement works, but I would like a separate message to appear for a non-numerical input such as "$boo", "ten", "idk").
puts "Candy Sold: "
candy_sold = gets.chomp.to_i
until candy_sold >= 0
if candy_sold < 0
puts "Please enter a positive number:"
candy_sold = gets.chomp.to_i
elsif candy_sold.class == String # This is where the issue is
puts "Please enter a positive number:"
candy_sold = gets.chomp.to_i
end
end
If I am understanding your question correct, you just want to allow only positive numbers. In this case, you can use the cover? method with a range.
puts "Candy Sold: "
candy_sold = gets.chomp
until ('0'..'9').cover? candy_sold
puts "Please enter a positive number"
candy_sold = gets.chomp
end
Candy Sold:
> Hello
=> Please enter a positive number
> -97
=> Please enter a positive number
> -0
=> Please enter a positive number
> 1
=> nil
If you check already converted number there is no way to tell if it was initially valid format or not. You have to compare with initial input somehow.
One of the solutions:
ask_for_amount = true
while ask_for_amount
candy_number_input = gets.chomp.strip
candy_sold = candy_number_input.to_i
if candy_number_input != candy_sold.to_s
puts "Please enter a valid positive number:"
elsif candy_sold < 0
puts "Please enter a positive number:"
else
ask_for_amount = false
end
end

If statement not working with gets() in Ruby

When I ask the user for input like this:
puts "Enter num: "
num = gets()
if num == 44
puts "Yeah"
end
unless num == 44
puts "No"
end
the output is "No" when I enter 44 when prompted. I can't figure out what's going on, so please help.
The ouput is "No" because when you use gets actually the input is taken as string, so a mismatch occurs. So for your logic to work you should convert it into integer
So this is the solution
puts "Enter num: "
num = gets().to_i
if num == 44
puts "Yeah"
end
unless num == 44
puts "No"
end
You can simply do:
gets.to_i
which will essentially chomp the newline character and convert to integer.
Example:
2.1.2-perf :020 > num = gets.to_i
44
=> 44
2.1.2-perf :021 > if num == 44
2.1.2-perf :022?> puts "Yeah"
2.1.2-perf :023?> end
Yeah
gets() by itself included the newline character. Use gets.chomp to remove that extra character. Then, call .to_i to convert to an integer. So: gets.chomp.to_i.

ruby using if inside loop with user input

I trying to make loop through if statement if user input is invalid it keep telling to enter number only or break if true
I tried this is my code
class String
def numeric?
Float(self) != nil rescue false
end
end
cond = false
puts "Enter number "
line = gets.chomp.strip
while cond == false
if (line.numeric? )
puts "Ok nice "
cond = true
else
puts "Please enter number only "
end
end
but it keep looping if the condition is false just printing "Please enter number only "
i will be very happy for any suggestion
Thank you
The problem is that after telling the user to just enter a number you don't read another number, you just loop back around.
The easiest way to fix this is to move the prompt and input into the while loop, a bit like this:
class String
def numeric?
Float(self) != nil rescue false
end
end
cond = false
while cond == false
puts "Enter number "
line = gets.chomp.strip
if (line.numeric? )
puts "Ok nice "
cond = true
else
puts "Please enter number only "
end
end
try this:
while cond == false
if (line.numeric? )
puts "Ok nice "
cond = true
else
puts "Please enter number only "
line = gets.chomp.strip
end
end
Right after overriding String method, try this:
while true
print "Enter number "
line = gets.chomp.strip
if line.numeric?
puts "Ok nice"
break
else
puts "Please enter number only"
end
end

Need help validating if user input is a number

I have the following code:
def say(msg)
puts "=> #{msg}"
end
def do_math(num1, num2, operation)
case operation
when '+'
num1.to_i + num2.to_i
when '-'
num1.to_i - num2.to_i
when '*'
num1.to_i * num2.to_i
when '/'
num1.to_f / num2.to_f
end
end
say "Welcome to my calculator!"
run_calculator = 'yes'
while run_calculator == 'yes'
say "What's the first number?"
num1 = gets.chomp
say "What's the second number?"
num2 = gets.chomp
say "What would you like to do?"
say "Enter '+' for Addition, '-' for Subtraction, '*' for Multiplication, or '/' for Division"
operation = gets.chomp
if num2.to_f == 0 && operation == '/'
say "You cannot devide by 0, please enter another value!"
num2 = gets.chomp
else
result = do_math(num1, num2, operation)
end
say "#{num1} #{operation} #{num2} = #{result}"
say "Would you like to do another calculation? Yes / No?"
run_calculator = gets.chomp
if run_calculator.downcase == 'no'
say "Thanks for using my calculator!"
elsif run_calculator.downcase == 'yes'
run_calculator = 'yes'
else
until run_calculator.downcase == 'yes' || run_calculator.downcase == 'no'
say "Please enter yes or no!"
run_calculator = gets.chomp
end
end
end
I need it to take the num1 and num2 variables that the user inputs and validate that they are numbers and return a message if they aren't.
I would like to use a Regex, but I don't know if I should create a method for this or just wrap it in a loop.
The Integer method will raise an exception when the given string is not a valid number, whereas to_i will fail silently (which I think is not desired behavior):
begin
num = Integer gets.chomp
rescue ArgumentError
say "Invalid number!"
end
If you want a regex solution, this will also work (although I recommend the method above):
num = gets.chomp
unless num =~ /^\d+$/
say "Invalid number!"
end
You would often see each section written something like this:
ERR_MSG = "You must enter a non-negative integer"
def enter_non_negative_integer(instruction, error_msg)
loop do
puts instruction
str = gets.strip
return str.to_i if str =~ /^\d+$/
puts error_msg
end
end
x1 = enter_non_negative_integer("What's the first number?", ERR_MSG)
x2 = enter_non_negative_integer("What's the second number?", ERR_MSG)
Here's possible dialog:
What's the first number?
: cat
You must enter a non-negative integer
What's the first number?
: 4cat
You must enter a non-negative integer
What's the first number?
: 22
#=> 22
What's the second number?
: 51
#=> 51
x1 #=> 22
x2 #=> 51

Resources