Vérifier si une variable est un entier


137

Rails 3 ou Ruby ont-ils un moyen intégré de vérifier si une variable est un entier?

Par exemple,

1.is_an_int #=> true
"dadadad@asdasd.net".is_an_int #=> false?


1
Plutôt que de vous soucier de savoir si une variable est un entier, vous devriez vérifier si la variable répond à to_i. Cela fait partie du "typage canard" de Ruby: s'il peut agir comme un entier, traitez-le comme tel.
The Tin Man le

4
@the Tin Man: Pas entièrement. "hello" .to_i renvoie 0, ce qui n'est peut-être pas ce que vous attendez.
EinLama le

1
@AnApprentice Pour votre information, kind_of?est un alias de is_a?.
Jacob Relkin

3
@JacobRelkin is_a?est légèrement différent; il demande si l'objet d'une instance d'une classe spécifique; kind_of?demande s'il s'agit d'une instance ou d'un enfant d'une classe spécifique. fido.is_a? Dogest vrai; fido.kind_of? Animalest vrai, par exemple.
Tom Harrison

Réponses:


274

Vous pouvez utiliser la is_a?méthode

>> 1.is_a? Integer
=> true
>> "dadadad@asdasd.net".is_a? Integer
=> false
>> nil.is_a? Integer
=> false

2
C'est très cool. cela fonctionne-t-il pour valider les adresses e-mail?
AnApprentice

65
@AnApprentice Depuis quand valider les adresses e-mail faisait-il partie de la question?
Jacob Relkin le

4
cela ne fonctionnera pas si le nombre est dans une chaîne comme "11111111"
Ricbermo

regardez ci-dessous Integer(obj) rescue false Cela ne fonctionnera pas pour "1" si vous voulez vérifier si cela convertira
mc.

4
@Ricbermo "1111111" est une chaîne. Une chaîne qui se trouve être convertible en et Integer.
Sqeaky

50

Si vous voulez savoir si un objet est un Integer ou quelque chose qui peut être converti de manière significative en un entier (sans inclure des choses comme "hello", qui to_isera converti en 0):

result = Integer(obj) rescue false

2
Peut-être que je suis juste un noob, mais cette modification m'aurait aidé. result = Integer (obj) rescue false.
John Curry

@JohnCurry, n'hésitez pas à modifier la réponse si vous pouvez l'améliorer. Voilà comment fonctionne SO.
Alex D

2
Je l'ai fait, il a été rejeté. "Cette modification s'écarte de l'intention originale du message" Mais peu importe, merci pour votre réponse, cela m'a aidé à résoudre mon problème!
John Curry

7
Integer ('08 ') échouera car la chaîne est interprétée comme octal, Integer ('08', 10) fonctionne bien. Au cas où.
Jong Bor Lee

1
Je ne sais pas si Integer(2.5) => 2c'est toujours une conversion significative.
mkataja

29

Utilisez une expression régulière sur une chaîne:

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

Si vous voulez vérifier si une variable est d'un certain type, vous pouvez simplement utiliser kind_of?:

1.kind_of? Integer #true
(1.5).kind_of? Float #true
is_numeric? "545"  #true
is_numeric? "2aa"  #false

C'est exactement ce que je cherchais le is_numeric?
workdreamer

Je pense que c'est proche, mais pas tout à fait correct. Par exemple, il échouera pour ".34". Le problème, je pense, est que dans \d+?le ?spécifie une correspondance non gourmande, alors que vous voulez probablement une correspondance facultative. Changer \d+?en \d*peut le résoudre, mais je voudrais le faire passer par une suite de tests pour être sûr. Cela ne correspond pas non plus à la notation hexadécimale ou exponentielle, mais je suis sûr que cela convient à certains cas d'utilisation.
Jeff

1
Pourquoi ne pas simplement utiliser cette expression rationnelle: \A\d+\z?
NARKOZ

1
Comparez avec le Integer(obj) rescue falsecode de @ alex-d ci-dessous; regexp est difficile à lire et son intention n'est pas claire. Les deux fonctionnent, je suis venu à cette question dans le but de réparer une expression rationnelle mal construite qui ne fonctionnait pas toujours :-)
Tom Harrison

17

Si vous n'êtes pas sûr du type de la variable (il pourrait s'agir d'une chaîne de caractères numériques), disons que c'était un numéro de carte de crédit passé dans les paramètres, donc ce serait à l'origine une chaîne, mais vous voulez vous assurer que ce n'est pas le cas. t avoir des caractères de lettre dedans, j'utiliserais cette méthode:

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

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

@Benny souligne un oubli de cette méthode, gardez ceci à l'esprit:

is_number? "01" # false. oops!

merci, vous sauvez ma journée. Pour tous ceux qui ont besoin de vérifier s'il flotte ou non, cela peut changer directement obj.to_s == obj.to_f.to_scomme dans mon cas.
ksugiarto

Edmund c'est malin! 🙌
siwalikm

Génial, je préfère cela à Integer ('123fh') et l'exception de sauvetage.
zw963

6

Vous pouvez utiliser le triple égal.

if Integer === 21 
    puts "21 is Integer"
end

5

Il y a var.is_a? Class(dans votre cas:) var.is_a? Integer; cela pourrait convenir à la facture. Ou il y a Integer(var), où il lancera une exception s'il ne peut pas l'analyser.


3

Une manière plus "de typage canard" est d'utiliser de respond_to?cette manière les classes "de type entier" ou "de type chaîne" peuvent également être utilisées

if(s.respond_to?(:match) && s.match(".com")){
  puts "It's a .com"
else
  puts "It's not"
end

2

Si vous ne avez pas besoin de convertir les valeurs zéro, je trouve les méthodes to_iet to_fd'être extrêmement utiles car ils convertir la chaîne en soit une valeur nulle (sinon convertible ou nul) ou réelle Integerou Floatvaleur.

"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: attention, la 0valeur entière n'est pas fausse, c'est la vérité ( !!0 #=> true) (merci @prettycoder)

ÉDITER

Ah je viens de découvrir les cas sombres ... semble ne se produire que si le numéro est en première position

"12blah".to_i => 12

0 est la vérité en rubis!
prettycoder

1
@prettycoder merci pour la mise au point, je vais corriger cela immédiatement dans la réponse
Cyril Duchon-Doris

1

Pour capitaliser sur la réponse d'Alex D , en utilisant des raffinements :

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

Plus tard, dans votre classe:

require 'core_ext/string/integerable'

class MyClass
  using CoreExtensions::Integerable

  def method
    'my_string'.integer?
  end
end

0

J'ai eu un problème similaire avant d'essayer de déterminer si quelque chose est une chaîne ou une sorte de nombre. J'ai essayé d'utiliser une expression régulière, mais ce n'est pas fiable pour mon cas d'utilisation. Au lieu de cela, vous pouvez vérifier la classe de la variable pour voir si elle est un descendant de la classe Numeric.

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

Dans cette situation, vous pouvez également remplacer l'un des descendants numériques: BigDecimal, Date :: Infinity, Integer, Fixnum, Float, Bignum, Rational, Complex


-1

Vous recherchez probablement quelque chose comme ceci:

Acceptez "2.0 ou 2.0 comme INT mais rejetez 2.1 et" 2.1 "

num = 2,0

si num.is_a? Chaîne num = Float (num) sauvetage fausse fin

new_num = Integer (num) rescue false

met num

met new_num

met num == new_num

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.