106

I want to simply check if a returned value from a form text field is a number i.e.: 12 , 12.5 or 12.75. Is there a simple way to check this, especially if the value is pulled as a param?

Mischa
  • 42,876
  • 8
  • 99
  • 111
user211662
  • 18,067
  • 10
  • 25
  • 19
  • um, the only thing is that the code works for is_a_number? works with the only exception being .02, or .3 numbers.... – user211662 Jan 19 '10 at 19:22
  • 7
    I much prefer this solution: http://stackoverflow.com/questions/5661466/test-if-string-is-a-number-in-ruby-on-rails/5661695 I don't know why so many people think a regexp would be better for that. – 2called-chaos Sep 17 '13 at 14:11

10 Answers10

239

You can use

12.is_a? Numeric

(Numeric will work for integers and floats.)

If it arrives as a string that might contain a representation of a valid number, you could use

class String
  def valid_float?
    true if Float self rescue false
  end
end

and then '12'.valid_float? will return true if you can convert the string to a valid float (e.g. with to_f).

geekQ
  • 29,027
  • 11
  • 62
  • 58
Peter
  • 127,331
  • 53
  • 180
  • 211
  • Sorry, this is Ruby on Rails ... Basically, I just want to be able to evaluate any input from the user whether it be .03 0.3, 2.2 THe latter two work, but I need to get the first input working :S – user211662 Jan 19 '10 at 20:22
  • 10
    ```Fixnum``` doesn't seem to work with floats. However, ```Numeric``` works fine. So ```1.234.is_a? Fixnum == false```, but ```1.234.is_a? Numeric == true```. – KurtPreston Nov 28 '12 at 15:35
  • This doesn't work with floats. Should use `1.1.is_a? Numeric` See http://stackoverflow.com/a/17668654/76486 – Brian Armstrong Jul 16 '13 at 05:29
  • 2
    Not working for me :( `pry(main)> '12'.is_a? Numeric => false` – Salil Jun 24 '16 at 06:46
  • @Salil obviously that will not work for you, `'12'` is a String. In that case check the string with Regex or any other possible solution. – edmundo096 May 27 '17 at 05:33
31

I usually just use Integer and Float these days.

1.9.2p320 :001 > foo = "343"
 => "343"
1.9.2p320 :003 > goo = "fg5"
 => "fg5"

1.9.2p320 :002 > Integer(foo) rescue nil
 => 343
1.9.2p320 :004 > Integer(goo) rescue nil
 => nil

1.9.2p320 :005 > Float(foo) rescue nil
 => 343.0
1.9.2p320 :006 > Float(goo) rescue nil
 => nil
daesu
  • 612
  • 7
  • 10
  • 3
    In ruby 2.6 you can also do the following: `Integer('343', exception: false) # 343` and `Integer('fg5', exception: false) # nil` ``` – Vlad Hilko Nov 30 '21 at 11:31
30

Just regexp it, it's trivial, and not worth thinking about beyond that:

v =~ /\A[-+]?[0-9]*\.?[0-9]+\Z/

(Fixed as per Justin's comment)

cwninja
  • 9,550
  • 1
  • 29
  • 22
  • 6
    In ruby, ^ and $ denote the beginning/end of a line, not of a string. This makes this ineffective to use as a means of sanitizing inputs (see http://guides.rubyonrails.org/security.html#regular-expressions). A better approach would be: `v.to_s =~ /\A[-+]?\d*\.?\d+\z/`. – Justin Aug 05 '13 at 14:34
  • This does not work for strings that represent exponential notation `irb(main):031:0> v = "0.7e1" => "0.7e1" irb(main):032:0> v =~ /\A[-+]?[0-9]*\.?[0-9]+\Z/ => nil ` – Stefan Musarra Mar 08 '23 at 19:00
16

You can add a:

validates_numericality_of :the_field

in your model.

See: http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#M002172

ryanprayogo
  • 11,587
  • 11
  • 51
  • 66
11

Just convert string twice:

num = '12'
num == num.to_i.to_s 
#=> true 

num = '3re'
num == num.to_i.to_s 
#=> false
Vlad Hilko
  • 1,104
  • 12
  • 17
  • Works not so bad with integers, but there are so many ways to fail if you want to follow this advice with floats (which is what the question asks about): `"7" == "7".to_f.to_s #=> false` ("7" vs "7.0") – David Stosik Oct 29 '16 at 07:50
  • You can do `num == num.to_i.to_s || num == num.to_f.to_s` – mannykary Jun 05 '18 at 05:30
  • you can also format both string using the "%" operator to guarantee that they both end in the same string – Jaacko Torus Jul 19 '20 at 20:41
6

I would suggest this one

def is_a_number?(str)
  !!(Float(str) rescue false)
end

> is_a_number?(1)
 => true

> is_a_number?(1.1)
 => true 

> is_a_number?('1')
 => true 

> is_a_number?('1.1')
 => true 

> is_a_number?('a')
 => false 

> is_a_number?(nil)
 => false
installero
  • 9,096
  • 3
  • 39
  • 43
4
irb(main):005:0> 1.1.is_a? Numeric
=> true
irb(main):006:0> 1.is_a? Numeric
=> true
irb(main):007:0> 'asd'.is_a? Numeric
=> false
Brian Armstrong
  • 19,707
  • 17
  • 115
  • 144
1

There was answer with Kernel#Float

But this variant is used with exception: false key and double bang to return boolean

class String
  def number?
    !!Float(self, exception: false)
  end
end
mechnicov
  • 12,025
  • 4
  • 33
  • 56
0

I'd rather use regexp matching, for example:

irb(main):015:0> 12.5.to_s.match?(/^-?\d+(\.\d+)?$/)
=> true
Kiryl Plyashkevich
  • 2,157
  • 19
  • 18
-5

String values always convert to 0 with .to_i

[14] pry(main)> 'Apple'.to_i > 0
=> false

[15] pry(main)> '101'.to_i > 0
=> true
Adrian Teh
  • 1,929
  • 18
  • 15