web-dev-qa-db-fra.com

Comment vérifier si une chaîne est essentiellement un entier entre guillemets en utilisant Ruby

J'ai besoin d'une fonction, is_an_integer, où

  • "12".is_an_integer? retourne vrai.
  • "blah".is_an_integer? retourne faux.

Comment puis-je faire cela en Ruby? Je voudrais écrire une regex mais je suppose qu'il existe un assistant pour cela que je ne suis pas au courant.

121
Tony

Vous pouvez utiliser des expressions régulières. Voici la fonction avec les suggestions de @ janm.

class String
    def is_i?
       !!(self =~ /\A[-+]?[0-9]+\z/)
    end
end

Une version modifiée d'après le commentaire de @wich:

class String
    def is_i?
       /\A[-+]?\d+\z/ === self
    end
end

Dans le cas où vous devez seulement vérifier les nombres positifs

  if !/\A\d+\z/.match(string_to_check)
      #Is not a positive number
  else
      #Is all good ..continue
  end  
130
Rado

Eh bien, voici le moyen facile:

class String
  def is_integer?
    self.to_i.to_s == self
  end
end

>> "12".is_integer?
=> true
>> "blah".is_integer?
=> false

Je ne suis pas d'accord avec les solutions qui provoquent une exception pour convertir la chaîne - les exceptions ne constituent pas un flux de contrôle, et vous pourriez aussi bien le faire de la bonne façon. Cela dit, ma solution ci-dessus ne traite pas les entiers non-base 10. Alors voici le moyen de faire avec sans recourir à des exceptions:

  class String
    def integer? 
      [                          # In descending order of likeliness:
        /^[-+]?[1-9]([0-9]*)?$/, # decimal
        /^0[0-7]+$/,             # octal
        /^0x[0-9A-Fa-f]+$/,      # hexadecimal
        /^0b[01]+$/              # binary
      ].each do |match_pattern|
        return true if self =~ match_pattern
      end
      return false
    end
  end
156
Sarah Mei

Vous pouvez utiliser Integer(str) et voir si cela soulève:

def is_num?(str)
  !!Integer(str)
rescue ArgumentError, TypeError
  false
end

Il convient de souligner que, bien que cela soit vrai pour "01", ça ne fait pas pour "09", simplement parce que 09 ne serait pas un littéral entier valide. Si ce n'est pas le comportement que vous souhaitez, vous pouvez ajouter 10 comme second argument de Integer, le nombre est donc toujours interprété en base 10.

63
sepp2k
"12".match(/^(\d)+$/)      # true
"1.2".match(/^(\d)+$/)     # false
"dfs2".match(/^(\d)+$/)    # false
"13422".match(/^(\d)+$/)   # true
25
Maciej Krasowski

Vous pouvez faire un one liner:

str = ...
int = Integer(str) rescue nil

if int
  int.times {|i| p i}
end

ou même

int = Integer(str) rescue false

En fonction de ce que vous essayez de faire, vous pouvez également utiliser directement un bloc begin end avec une clause rescue:

begin
  str = ...
  i = Integer(str)

  i.times do |j|
    puts j
  end
rescue ArgumentError
  puts "Not an int, doing something else"
end
22
Robert Klemme
class String
  def integer?
    Integer(self)
    return true
  rescue ArgumentError
    return false
  end
end
  1. Il n'est pas préfixé par is_. Je trouve ça idiot sur les méthodes de questionmark, j'aime bien "04".integer? beaucoup mieux que "foo".is_integer?.
  2. Il utilise la solution sensible de sepp2k, qui passe pour "01" et autres choses de ce genre.
  3. Orienté objet, yay.
8
August Lilleaas

Ruby 2.6.0 permet transtyper un entier sans lever d'exception , et retournera nil si la conversion échoue. Et comme nil se comporte généralement comme false en Ruby, vous pouvez facilement rechercher un entier, comme ceci:

if Integer(my_var, exception: false)
  # do something if my_var can be cast to an integer
end
8
Timitry

La meilleure méthode consiste à utiliser Float

val = Float "234" rescue nil

Float "234" rescue nil #=> 234.0

Float "abc" rescue nil #=> nil

Float "234abc" rescue nil #=> nil

Float nil rescue nil #=> nil

Float "" rescue nil #=> nil

Integer est également bon mais il retournera 0 pour Integer nil

6
shiva

Je préfère:

config/initializers/string.rb

class String
  def number?
    Integer(self).is_a?(Integer)
  rescue ArgumentError, TypeError
    false
  end
end

et alors:

[218] pry(main)> "123123123".number?
=> true
[220] pry(main)> "123 123 123".gsub(/ /, '').number?
=> true
[222] pry(main)> "123 123 123".number?
=> false

ou vérifiez le numéro de téléphone:

"+34 123 456 789 2".gsub(/ /, '').number?
5
skozz

Une façon beaucoup plus simple pourrait être

/(\D+)/.match('1221').nil? #=> true
/(\D+)/.match('1a221').nil? #=> false
/(\D+)/.match('01221').nil? #=> true
4
gouravtiwari21

Personnellement, j'apprécie l'approche d'exception, bien que je la rende un peu plus concise:

class String
  def integer?(str)
    !!Integer(str) rescue false
  end
end

Cependant, comme d'autres l'ont déjà indiqué, cela ne fonctionne pas avec les chaînes Octal.

3
eightbitraptor
  def isint(str)
    return !!(str =~ /^[-+]?[1-9]([0-9]*)?$/)
  end
3
Amal Kumar S

Cela pourrait ne pas convenir à tous les cas en utilisant simplement:

"12".to_i   => 12
"blah".to_i => 0

pourrait aussi faire pour certains.

Si c'est un nombre et pas 0, il retournera un nombre. S'il renvoie 0, c'est une chaîne ou 0.

2
three

Voici ma solution:

# /initializers/string.rb
class String
  IntegerRegex = /^(\d)+$/

  def integer?
    !!self.match(IntegerRegex)
  end
end

# any_model_or_controller.rb
'12345'.integer? # true
'asd34'.integer? # false

Et voici comment cela fonctionne:

  • /^(\d)+$/ est une expression regex permettant de rechercher des chiffres dans une chaîne. Vous pouvez tester vos expressions et résultats regex à l’adresse http://rubular.com/ .
  • Nous le sauvegardons dans une constante IntegerRegex afin d'éviter une allocation de mémoire inutile chaque fois que nous l'utilisons dans la méthode.
  • integer? Est une méthode interrogative qui devrait renvoyer true ou false.
  • match est une méthode sur chaîne qui correspond aux occurrences de l'expression d'expression rationnelle donnée dans l'argument et renvoie les valeurs correspondantes ou nil.
  • !! Convertit le résultat de la méthode match en un booléen équivalent.
  • Et déclarer la méthode dans la classe String existante est un correctif monkey, qui ne modifie en rien les fonctionnalités String existantes, mais ajoute simplement une autre méthode nommée integer? À tout objet String.
2
Sachin

Ruby 2.4 a Regexp#match? : (avec un ?)

def integer?(str)
  /\A[+-]?\d+\z/.match? str
end

Pour les anciennes Ruby, il y a Regexp#=== . Et bien que l’utilisation directe de l’opérateur d’égalité de cas soit généralement évitée, elle est très nette ici:

def integer?(str)
  /\A[+-]?\d+\z/ === str
end

integer? "123"    # true
integer? "-123"   # true
integer? "+123"   # true

integer? "a123"   # false
integer? "123b"   # false
integer? "1\n2"   # false
2
Stefan

Pour les cas plus généralisés (y compris les nombres avec un point décimal), vous pouvez essayer la méthode suivante:

def number?(obj)
  obj = obj.to_s unless obj.is_a? String
  /\A[+-]?\d+(\.[\d]+)?\z/.match(obj)
end

Vous pouvez tester cette méthode dans une session irb:

(irb)
>> number?(7)
=> #<MatchData "7" 1:nil>
>> !!number?(7)
=> true
>> number?(-Math::PI)
=> #<MatchData "-3.141592653589793" 1:".141592653589793">
>> !!number?(-Math::PI)
=> true
>> number?('hello world')
=> nil
>> !!number?('hello world')
=> false

Pour une explication détaillée de la regex impliquée ici, consultez cet article de blog :)

1
tg_freelancer

En développant la réponse de @ rado ci-dessus, on pourrait également utiliser une déclaration ternaire pour forcer le retour de booléens vrais ou faux sans utiliser de double-coup. Certes, la version à double négation logique est plus concise, mais probablement plus difficile à lire pour les nouveaux arrivants (comme moi).

class String
  def is_i?
     self =~ /\A[-+]?[0-9]+\z/ ? true : false
  end
end
1
adeluccar

J'aime ce qui suit, simple:

def is_integer?(str)
  str.to_i != 0 || str == '0' || str == '-0'
end

is_integer?('123')
=> true

is_integer?('sdf')
=> false

is_integer?('-123')
=> true

is_integer?('0')
=> true

is_integer?('-0')
=> true

Attention cependant:

is_integer?('123sdfsdf')
=> true
0
schmijos