Test si la chaîne est un nombre dans Ruby on Rails
J'ai de la suite dans mon contrôleur d'application:
def is_number?(object)
true if Float(object) rescue false
end
et de la condition suivante dans mon controller:
if mystring.is_number?
end
L'état est en train de jeter un undefined method
erreur. Je devine que j'ai défini is_number
au mauvais endroit...?
- Je sais que beaucoup de gens sont là à cause de codeschool de Rails pour les Zombies de Test de la classe. Juste attendre pour lui de garder en expliquant. Les tests ne sont pas censés passer --- son OK pour avez-vous test échoue dans l'erreur, vous pouvez toujours patch rails à inventer des méthodes telles que l'auto.is_number?
- La accepté de répondre échoue sur des cas comme "1,000" et est un 39x plus lent que d'utiliser une regex approche. Voir ma réponse ci-dessous.
Vous devez vous connecter pour publier un commentaire.
Créer
is_number?
Méthode.Créer une méthode d'assistance:
Et ensuite appeler comme ceci:
Étendre
String
Classe.Si vous voulez être en mesure d'appeler
is_number?
directement sur la chaîne, au lieu de passer en tant que paramètre à ta fonction d'assistance, vous devez définiris_number?
comme une extension de laString
classe, comme suit:Et puis vous pouvez l'appeler avec:
to_f
ci-dessus, et Float() ne présentent pas ce comportement:Float("330.346.11")
soulèveArgumentError: invalid value for Float(): "330.346.11"
lib/core_ext/string.rb
.is_number?(string)
peu de travaux Ruby 1.9. Peut-être que c'est une partie de Rails ou de 1,8?String.is_a?(Numeric)
œuvres. Voir aussi stackoverflow.com/questions/2095493/..../^\d+$/
n'est pas un coffre-fort regexp en Ruby,/\A\d+\Z/
est. (par exemple, "42\nsome texte" serait de retourtrue
)/^\d+$/
si vous traitez avec des lignes, mais dans ce cas, il est à propos de début et de fin de chaîne, donc/\A\d+\Z/
.Voici un test pour le commun des moyens pour remédier à ce problème. Notez qui celui que vous devez utiliser dépend probablement sur le ratio de faux cas attendus.
Si la performance n'est pas question d'utiliser ce que vous aimez. 🙂
Entier vérifiant les détails:
Float vérifiant les détails:
En s'appuyant sur l'exception soulevée n'est pas le plus rapide, lisible, ni de solution fiable.
Je ferais le suivant :
expect(my_string).to match(/^[0-9]+$/)
my_string =~ /\A-?(\d+)?\.?\d+\Z/
il vous permet de faire '.1', '-0.1", ou "12", mais pas " ou " - "ou"."non, vous êtes juste à l'aide de ce mal. votre is_number? a un argument. vous l'avez appelé sans argument
que vous devriez faire is_number?(mystring)
mystring
est en effet une Chaîne de caractères,mystring.is_a?(Integer)
sera toujours faux. On dirait qu'il veut un résultat commeis_number?("12.4") #=> true
Tl;dr: Utiliser une regex approche. Il est 39x plus rapide que l'approche de sauvetage dans l'acceptation de réponse et de prise en charge des cas comme "1,000"
--
La accepté de répondre par @Jakob S œuvres, pour la plupart, mais la capture des exceptions peuvent être vraiment lent. En outre, l'approche de sauvetage échoue sur une chaîne comme "1,000".
Nous allons définir les méthodes:
Et maintenant certains des cas de test:
Et un peu de code à exécuter les cas de test:
Ici est la sortie du cas de test:
De temps pour faire quelques tests de performance:
Et les résultats:
5.4e-29
. Je suppose que votre regex pourrait être modifié pour accepter ceux aussi.c'est de cette façon que je le fais, mais je pense trop, il doit y avoir une meilleure façon
Dans les rails 4, vous avez besoin de mettre
require File.expand_path('../../lib', __FILE__) + '/ext/string'
dans votre config/application.rb
Si vous préférez ne pas utiliser les exceptions dans le cadre de la logique, vous pouvez essayer ceci:
Ou, si vous voulez qu'il fonctionne dans toutes les classes d'objet, remplacer
class String
avecclass Object
un convertir soi à une chaîne:!!(self.to_s =~ /^-?\d+(\.\d*)?$/)
nil?
zéro est trurthy sur ruby, de sorte que vous pouvez juste faire!!(self =~ /^-?\d+(\.\d*)?$/)
!!
certainement œuvres. Au moins un Rubis style guide (github.com/bbatsov/ruby-style-guide) a suggéré d'éviter!!
en faveur de.nil?
pour des raisons de lisibilité, mais j'ai vu!!
utilisé dans les dépôts, et je pense que c'est une belle façon de convertir un booléen. J'ai édité la réponse.Comme des Rubis 2.6.0, le numérique cast-méthodes ont l'option
exception
-argument [1]. Cela nous permet d'utiliser les méthodes intégrées sans l'aide d'exceptions que le contrôle de flux:Par conséquent, vous n'avez pas à définir votre propre méthode, mais peut vérifier variables comme par exemple
utiliser la fonction suivante:
donc,
is_numeric? "1.2f"
= falseis_numeric? "1.2"
= trueis_numeric? "12f"
= falseis_numeric? "12"
= true"0"
. Notez également que la méthode.try
ne fait pas partie de la librairie principale et n'est disponible que si vous êtes, y compris ActiveSupport."12"
, de sorte que votre quatrième exemple, dans cette question, est faux."12.10"
et"12.00"
aussi échouer.Quelle stupidité est-ce la solution?