163 votes

Analyse sûre des nombres entiers en Ruby

J'ai une chaîne, disons '123' et je veux le convertir en un entier 123 .

Je sais que vous pouvez simplement faire some_string.to_i mais qui convertit 'lolipops' a 0 ce qui n'est pas l'effet que j'ai en tête. Je veux que ça m'explose à la figure quand j'essaie de convertir quelque chose d'invalide, avec une belle et douloureuse Exception . Sinon, je ne peux pas faire la différence entre un valide 0 et quelque chose qui n'est pas un numéro du tout.

EDITAR: Je cherchais la manière standard de le faire, sans avoir recours à l'utilisation de regex.

6voto

J'ai été confronté à ce problème dans mon dernier projet, et ma mise en œuvre était similaire, mais un peu différente :

class NotAnIntError < StandardError 
end

class String
  def is_int?    
    self =~ /^-?[0-9]+$/
  end

  def safe_to_i
    return self.to_i if is_int?
    raise NotAnIntError, "The string '#{self}' is not a valid integer.", caller
  end
end

class Integer
  def safe_to_i
    return self
  end            
end

class StringExtensions < Test::Unit::TestCase

  def test_is_int
    assert "98234".is_int?
    assert "-2342".is_int?
    assert "02342".is_int?
    assert !"+342".is_int?
    assert !"3-42".is_int?
    assert !"342.234".is_int?
    assert !"a342".is_int?
    assert !"342a".is_int?
  end

  def test_safe_to_i
    assert 234234 == 234234.safe_to_i
    assert 237 == "237".safe_to_i
    begin
      "a word".safe_to_i
      fail 'safe_to_i did not raise the expected error.'
    rescue NotAnIntError 
      # this is what we expect..
    end
  end

end

3voto

Paul Wicks Points 13205
someString = "asdfasd123"
number = someString.to_i
if someString != number.to_s
  puts "oops, this isn't a number"
end

Ce n'est probablement pas la façon la plus propre de le faire, mais cela devrait fonctionner.

1voto

metavida Points 911

Re : La réponse de Chris

Votre implémentation laisse passer des choses comme "1a" ou "b2". Que diriez-vous de ceci à la place ?

def safeParse2(strToParse)
  if strToParse =~ /\A\d+\Z/
    strToParse.to_i
  else
    raise Exception
  end
end

["100", "1a", "b2", "t"].each do |number|
  begin
    puts safeParse2(number)
  rescue Exception
    puts "#{number} is invalid"
  end
end

Ces sorties :

100
1a is invalid
b2 is invalid
t is invalid

0 votes

Pour être pédant, la mention de différentes ancres regex selon @pje et utilisées peut être incorrecte selon le comportement souhaité. Considérez plutôt l'utilisation de \z à la place de \Z comme la description de l'ancre Z majuscule est la suivante : "Correspond à la fin de la chaîne. Si la chaîne de caractères se termine par un saut de ligne, elle correspond juste avant le saut de ligne " -- ruby-doc.org/core-2.1.1/Regexp.html

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X