Sprawdzanie, czy zmienna jest liczbą całkowitą

137

Czy Rails 3 lub Ruby mają wbudowany sposób sprawdzania, czy zmienna jest liczbą całkowitą?

Na przykład,

1.is_an_int #=> true
"[email protected]".is_an_int #=> false?
Uczeń
źródło
możliwy duplikat Czy ruby ​​1.9.2 ma is_a? funkcjonować?
Andrew Grimm
1
Zamiast dbać o to, czy zmienna jest liczbą całkowitą, powinieneś sprawdzić, czy zmienna odpowiada to_i. To część "kaczego pisania" Rubiego: jeśli może zachowywać się jak liczba całkowita, traktuj ją jak jedną.
Tin Man
4
@ The Tin Man: Nie do końca. „hello” .to_i zwraca 0, co może nie być tym, czego oczekujesz.
EinLama,
1
@AnApprentice Dla twojej informacji, kind_of?to alias do is_a?.
Jacob Relkin
3
@JacobRelkin is_a?jest nieco inny; pyta, czy obiekt instancji określonej klasy; kind_of?pyta, czy jest to instancja lub dziecko określonej klasy. fido.is_a? Dogjest prawdziwy; fido.kind_of? Animaljest na przykład prawdą.
Tom Harrison,

Odpowiedzi:

274

Możesz użyć is_a?metody

>> 1.is_a? Integer
=> true
>> "[email protected]".is_a? Integer
=> false
>> nil.is_a? Integer
=> false
mportiz08
źródło
2
To bardzo fajnie. czy to działa, aby sprawdzić poprawność adresów e-mail?
AnApprentice,
65
@AnApprentice Od kiedy sprawdzanie poprawności adresów e-mail było częścią pytania?
Jacob Relkin,
4
to nie zadziała, jeśli liczba jest w postaci ciągu, takiego jak „11111111”
Ricbermo,
spójrz poniżej Integer(obj) rescue false To nie zadziała dla "1", jeśli chcesz sprawdzić, czy nastąpi konwersja
mc.
4
@Ricbermo "1111111" to ciąg. String, który można zamienić na i Integer.
Sqeaky
50

Jeśli chcesz wiedzieć, czy obiekt jest Integer lub czymś, co można w znaczący sposób przekonwertować na liczbę całkowitą (NIE obejmuje rzeczy takich jak "hello", które to_izostaną przekonwertowane na 0):

result = Integer(obj) rescue false
Alex D.
źródło
2
Może jestem tylko noobem, ale ta poprawka by mi pomogła. wynik = Integer (obj) rescue false.
John Curry,
@JohnCurry, możesz edytować odpowiedź, jeśli możesz ją poprawić. Tak działa SO.
Alex D
2
Zrobiłem, został odrzucony. „Ta zmiana odbiega od pierwotnego celu posta” Ale mimo wszystko, dziękuję za odpowiedź, pomogło mi to rozwiązać mój problem!
John Curry,
7
Liczba całkowita ('08 ') nie powiedzie się, ponieważ ciąg jest interpretowany jako ósemkowy, liczba całkowita ('08', 10) działa dobrze. W razie czego.
Jong Bor Lee,
1
Nie jestem pewien, czy Integer(2.5) => 2zawsze jest to znacząca konwersja.
mkataja
29

Użyj wyrażenia regularnego w ciągu:

def is_numeric?(obj) 
   obj.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/) == nil ? false : true
end

Jeśli chcesz sprawdzić, czy zmienna jest określonego typu, możesz po prostu użyć kind_of?:

1.kind_of? Integer #true
(1.5).kind_of? Float #true
is_numeric? "545"  #true
is_numeric? "2aa"  #false
Jacob Relkin
źródło
To jest dokładnie to, czego szukałem is_numeric?
workdreamer
Myślę, że to jest blisko, ale nie do końca poprawne. Na przykład nie powiedzie się dla „.34”. Myślę, że problem polega na tym, że w \d+?specyfikacji ?określa niechciane dopasowanie, podczas gdy prawdopodobnie chcesz opcjonalnego dopasowania. Zmiana \d+?na \d*może to naprawić, ale chciałbym przeprowadzić go przez zestaw testów, aby się upewnić. To również nie będzie pasowało do notacji szesnastkowej lub wykładniczej, ale jestem pewien, że jest to dobre w niektórych przypadkach użycia.
Jeff
1
Dlaczego po prostu nie korzystać z tego wyrażenia regularnego: \A\d+\z?
NARKOZ
1
Porównaj z Integer(obj) rescue falsekodem z @ alex-d poniżej; wyrażenie regularne jest trudne do odczytania i nie jest jasne w swoim celu. Obie prace, doszedłem do tego pytania, próbując naprawić źle skonstruowane wyrażenie regularne, które nie zawsze działało :-)
Tom Harrison
17

Jeśli nie masz pewności co do typu zmiennej (może to być ciąg znaków liczbowych), powiedz, że był to numer karty kredytowej przekazany do parametrów, więc pierwotnie byłby to ciąg, ale chcesz się upewnić, że tak nie jest nie zawiera żadnych liter, użyłbym tej metody:

    def is_number?(obj)
        obj.to_s == obj.to_i.to_s
    end

    is_number? "123fh" # false
    is_number? "12345" # true

@Benny zwraca uwagę na przeoczenie tej metody, pamiętaj o tym:

is_number? "01" # false. oops!
bigpotato
źródło
dzięki, ratujesz mój dzień. Dla każdego, kto musi sprawdzić, czy pływa, czy nie, może zmienić się bezpośrednio na obj.to_s == obj.to_f.to_stak jak w moim przypadku.
ksugiarto
Edmund, to sprytne! 🙌
siwalikm
Super, wolę to niż Integer ('123fh') i wyjątek ratunkowy.
zw963
6

Możesz użyć Triple Equal.

if Integer === 21 
    puts "21 is Integer"
end
Tsoodol
źródło
5

Jest var.is_a? Class(w twoim przypadku var.is_a? Integer:); to mogłoby pasować do rachunku. Lub jest Integer(var), gdzie zgłosi wyjątek, jeśli nie może go przeanalizować.

Groxx
źródło
3

Bardziej „kaczkowate” sposobem jest użycie w respond_to?ten sposób klas typu „integer-like” lub „string-like”

if(s.respond_to?(:match) && s.match(".com")){
  puts "It's a .com"
else
  puts "It's not"
end
vish
źródło
2

W przypadku, gdy nie trzeba konwertować wartości zerowe, znaleźć sposoby to_ii to_fbyć bardzo przydatna, ponieważ będą one przekształcić łańcuch albo do wartości zerowej (jeśli nie jest zamienny lub zerowy) lub rzeczywiste Integerlub Floatwartości.

"0014.56".to_i # => 14
"0014.56".to_f # => 14.56
"0.0".to_f # => 0.0
"not_an_int".to_f # 0
"not_a_float".to_f # 0.0

"0014.56".to_f ? "I'm a float" : "I'm not a float or the 0.0 float" 
# => I'm a float
"not a float" ? "I'm a float" : "I'm not a float or the 0.0 float" 
# => "I'm not a float or the 0.0 float"

EDIT2: uważaj, 0wartość całkowita nie jest błędna, to prawda ( !!0 #=> true) (dzięki @prettycoder)

EDYTOWAĆ

Ach, właśnie dowiedziałem się o ciemnych przypadkach ... wydaje się, że dzieje się to tylko wtedy, gdy liczba jest na pierwszym miejscu

"12blah".to_i => 12
Cyril Duchon-Doris
źródło
0 jest prawdą w rubinie!
prettycoder
1
@prettycoder dzięki za ostrzeżenie, naprawię to natychmiast w odpowiedzi
Cyril Duchon-Doris
1

Aby wykorzystać odpowiedź Alexa D , używając zawężeń :

module CoreExtensions
  module Integerable
    refine String do
      def integer?
        Integer(self)
      rescue ArgumentError
        false
      else
        true
      end
    end
  end
end

Później w Twojej klasie:

require 'core_ext/string/integerable'

class MyClass
  using CoreExtensions::Integerable

  def method
    'my_string'.integer?
  end
end
Vadym Tyemirov
źródło
0

Miałem podobny problem, zanim spróbowałem określić, czy coś jest ciągiem znaków lub jakąkolwiek liczbą. Próbowałem użyć wyrażenia regularnego, ale nie jest to wiarygodne w moim przypadku użycia. Zamiast tego możesz sprawdzić klasę zmiennej, aby zobaczyć, czy jest ona potomkiem klasy Numeric.

if column.class < Numeric
  number_to_currency(column)
else
  column.html_safe
end

W tej sytuacji możesz również podstawić dowolny z potomków Numeric: BigDecimal, Date :: Infinity, Integer, Fixnum, Float, Bignum, Rational, Complex

penguincoder
źródło
-1

Prawdopodobnie szukasz czegoś takiego:

Zaakceptuj „2.0 lub 2.0” jako INT, ale odrzuć 2.1 i 2.1

num = 2,0

if num.is_a? String num = Float (num) ratuj fałszywy koniec

new_num = Integer (num) rescue false

stawia num

umieszcza nowy_num

umieszcza num == nowy_num

Owais Akbani
źródło