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.
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
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
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.
"12".match(/^(\d)+$/) # true
"1.2".match(/^(\d)+$/) # false
"dfs2".match(/^(\d)+$/) # false
"13422".match(/^(\d)+$/) # true
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
class String
def integer?
Integer(self)
return true
rescue ArgumentError
return false
end
end
is_
. Je trouve ça idiot sur les méthodes de questionmark, j'aime bien "04".integer?
beaucoup mieux que "foo".is_integer?
."01"
et autres choses de ce genre.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
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
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?
Une façon beaucoup plus simple pourrait être
/(\D+)/.match('1221').nil? #=> true
/(\D+)/.match('1a221').nil? #=> false
/(\D+)/.match('01221').nil? #=> true
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.
def isint(str)
return !!(str =~ /^[-+]?[1-9]([0-9]*)?$/)
end
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.
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/ .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.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.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
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 :)
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
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