Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine numeric value when using str.to_f in Ruby?

I'm trying to catch the difference between a numeric string vs. an arbitrary string:

'0'.to_f
#=> 0.0

'hello'.to_f
#=> 0.0

Both of the above return a Float. How do I catch the difference if the user inputs the actual value '0' or if the user inputs the value 'hello'?

I am trying to create a simple Celsius to Fahrenheit calculator. If the user inputs "hello" the program should output Please type in a number: but if the user types in 0 then the program should output the correct Fahrenheit calculation.

like image 871
Clever Programmer Avatar asked Dec 10 '22 21:12

Clever Programmer


2 Answers

Use this:

number = Float( string_to_convert ) rescue nil
if number.nil? 
  puts "#{string_to_convert} is not a number"
else
  # DO the conversion
end

This will use a sensible set of rules for converting String values into Floats, supporting negative numbers, scientific notation, whilst not requiring you write a regular expression to try and capture all the valid ways of expressing floating point numbers in Ruby.

The rescue is required to catch the error from a failed conversion.


Potentially better Ruby code for your particular purpose (and combining design from Tamer's answer with feedback from Stefan in comments):

begin
  number = Float( string_to_convert )
rescue ArgumentError
  puts "'#{string_to_convert}' is not a number"
else
  # Do the conversion, using number variable
end

However, if the program flow is more complicated than input-or-bust-then-repeat, I still find the one-liner can be useful - provided of course you either raise an error later or can deal with missing values because the conversion to a Float failed.

like image 157
Neil Slater Avatar answered Mar 07 '23 09:03

Neil Slater


You could use a regular expression like:

/
\A   # anchor on start of a string, so there there is nothing more than float allowed
\-?  # optional minus
\d+  # non-empty row of digits
(
 \.  # dot
 \d+ # another row of digits
)?   # ? means both of the above are optional
\z   # anchor on end of a string, so there there is nothing more than float allowed
/x

single line version: /\A\-?\d+(\.\d+)?\z/

In typical use-case, Float( ) might be better, but using a regex separates you from Ruby's definition of Float literal, that can come handy if i.e. you want to allow a comma as decimal mark, or thousand separator (Ruby will only allow . and _ respectively). Regex match will also just return true or false, that can be useful if you want to avoid exception handling - ArgumentError thrown by Float( ) on fail is pretty generic, so it might get thrown by other nearby method call, and thus can get difficult to handle properly, or just make your code ugly.

like image 41
Borsunho Avatar answered Mar 07 '23 08:03

Borsunho