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
"dadadad@asdasd.net".is_an_int #=> false?


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
>> "dadadad@asdasd.net".is_a? Integer
=> false
>> nil.is_a? Integer
=> false

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

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

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!

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

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


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

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

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

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


-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

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.