Jak mogę sprawdzić, czy wartość jest liczbą?

82

Chcę po prostu sprawdzić, czy zwracana wartość z pola tekstowego formularza to liczba, tj .: 12, 12,5 lub 12,75. Czy istnieje prosty sposób, aby to sprawdzić, zwłaszcza jeśli wartość jest pobierana jako param?

user211662
źródło
um, jedyną rzeczą jest to, że kod działa dla is_a_number? działa z jedynym wyjątkiem .02 lub .3 liczb ....
user211662
7
O wiele bardziej wolę to rozwiązanie: stackoverflow.com/questions/5661466/… Nie wiem, dlaczego tak wiele osób uważa, że ​​regexp byłby do tego lepszy.
2called-chaos

Odpowiedzi:

26

Po prostu powtórz to, jest to trywialne i nie warto o tym myśleć:

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

(Naprawiono zgodnie z komentarzem Justina)

cwninja
źródło
5
W ruby, ^ i $ oznaczają początek / koniec wiersza, a nie napis. To sprawia, że ​​jest to nieskuteczne jako środek do odkażania danych wejściowych (patrz guide.rubyonrails.org/security.html#regular-expressions ). Lepszym rozwiązaniem byłoby: v.to_s =~ /\A[-+]?\d*\.?\d+\z/.
Justin
207

Możesz użyć

12.is_a? Numeric

( Numericbędzie działać dla liczb całkowitych i zmiennoprzecinkowych).

Jeśli pojawi się jako ciąg, który może zawierać reprezentację prawidłowej liczby, możesz użyć

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

a następnie '12'.valid_float?zwróci wartość true, jeśli możesz przekonwertować ciąg na prawidłową liczbę zmiennoprzecinkową (np. za pomocą to_f).

Piotr
źródło
Niestety, to jest Ruby on Rails ... Zasadniczo, po prostu chcę, aby móc oceniać żadnych danych od użytkownika, czy to będzie 0,03 0,3 2,2 Te dwa ostatnie prace, ale muszę dostać pierwszą pracę wejścia: S
user211662
10
Fixnumnie działa z pływakami. Jednak Numericdziała dobrze. Więc 1.234.is_a? Fixnum == false, ale 1.234.is_a? Numeric == true.
KurtPreston
To nie działa z pływakami. Należy użyć 1.1.is_a? NumericZobacz stackoverflow.com/a/17668654/76486
Brian Armstrong
1
Nie działa dla mnie :(pry(main)> '12'.is_a? Numeric => false
Salil
@Salil oczywiście to nie zadziała, '12'to String. W takim przypadku sprawdź ciąg za pomocą Regex lub innego możliwego rozwiązania.
edmundo096
27

Obecnie zwykle używam po prostu liczb Integer i Float.

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
źródło
7

Po prostu dwukrotnie przekonwertuj ciąg:

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

num = '3re'
num == num.to_i.to_s 
#=> false
Evan Ross
źródło
Nie działa tak źle z liczbami całkowitymi, ale jest tak wiele sposobów na niepowodzenie, jeśli chcesz zastosować się do tej rady z liczbami zmiennoprzecinkowymi (o co chodzi w pytaniu): "7" == "7".to_f.to_s #=> false(„7” vs „7,0”)
David Stosik
Możesz to zrobićnum == num.to_i.to_s || num == num.to_f.to_s
mannykary
możesz również sformatować oba ciągi za pomocą operatora „%”, aby zagwarantować, że oba kończą się tym samym ciągiem
Jaacko Torus
5

Sugerowałbym ten

def is_number?
  self.to_f == self
end

> 15.is_number?
=> true
> 15.0.is_number?
=> true
> 'Not a number'.is_number?
=> false
> (0/0.0).is_number?
=> false
installero
źródło
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
źródło
7
„1.1” .is_a? Numeric => false
Waclock,
Jak poradzisz sobie z problemem konwersji ciągów? OP stwierdza, że ​​pochodzi z pola tekstowego.
schlingel
-5

Wartości ciągów zawsze są konwertowane na 0 z .to_i

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

[15] pry(main)> '101'.to_i > 0
=> true
Adrian Teh
źródło
A co z skrajnymi przypadkami? Jeśli liczba jest równa 0 lub ujemna, test da fałszywie negatywny wynik.
tsikov
Jeszcze gorzej '1AB2'.to_i zwróciłoby 1 dla czegoś, co wyraźnie nie jest liczbą całkowitą ...
Thomas Bindzus