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?


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)


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).


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


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

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

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

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

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.