Frage

Ich habe zum Beispiel eine Schnur '123', und ich möchte es konvertieren 123.

Ich weiß, dass du es einfach tun kannst some_string.to_i, aber das konvertiert 'lolipops' Zu 0, was nicht der Effekt ist, den ich im Sinn habe.Ich möchte, dass es mir um die Ohren fliegt, wenn ich versuche, etwas Ungültiges in ein schönes und schmerzhaftes umzuwandeln Exception.Ansonsten kann ich nicht zwischen einem gültigen unterscheiden 0 und etwas, das überhaupt keine Zahl ist.

BEARBEITEN: Ich suchte nach der Standardmethode ohne Regex-Tricks.

War es hilfreich?

Lösung

Ruby verfügt über diese integrierte Funktionalität:

Integer('1001')                                    # => 1001  
Integer('1001 nights')  
# ArgumentError: invalid value for Integer: "1001 nights"  

Wie in der Antwort von erwähnt Joseph Pecoraro, möchten Sie möglicherweise auf Zeichenfolgen achten, bei denen es sich um gültige nichtdezimale Zahlen handelt, z. B. solche, die mit beginnen 0x für Hex und 0b für binäre und möglicherweise schwierigere Zahlen, die mit Null beginnen und als Oktal geparst werden.

Ruby 1.9.2 hat ein optionales zweites Argument für Radix hinzugefügt, sodass das obige Problem vermieden werden kann:

Integer('23')                                     # => 23
Integer('0x23')                                   # => 35
Integer('023')                                    # => 19
Integer('0x23', 10)
# => #<ArgumentError: invalid value for Integer: "0x23">
Integer('023', 10)                                # => 23

Andere Tipps

Das könnte funktionieren:

i.to_i if i.match(/^\d+$/)

Beachten Sie auch die Auswirkungen, die die derzeit akzeptierte Lösung auf das Parsen von Hex-, Oktal- und Binärzahlen haben kann:

>> Integer('0x15')
# => 21  
>> Integer('0b10')
# => 2  
>> Integer('077')
# => 63

In Ruby-Zahlen, die mit beginnen 0x oder 0X sind Hex, 0b oder 0B sind binär und gerecht 0 sind oktal.Wenn dies nicht das gewünschte Verhalten ist, können Sie es mit einigen anderen Lösungen kombinieren, die zunächst prüfen, ob die Zeichenfolge mit einem Muster übereinstimmt.Wie /\d+/ reguläre Ausdrücke usw.

Ein weiteres unerwartetes Verhalten bei der akzeptierten Lösung (mit 1.8 ist 1.9 in Ordnung):

>> Integer(:foobar)
=> 26017
>> Integer(:yikes)
=> 26025

Wenn Sie also nicht sicher sind, was übergeben wird, stellen Sie sicher, dass Sie eine hinzufügen .to_s.

Mir gefällt Myrons Antwort, aber er leidet an der Ruby-Krankheit „Ich verwende Java/C# nicht mehr, daher werde ich die Vererbung nie wieder verwenden.“.Das Öffnen eines Kurses kann mit Gefahren verbunden sein und sollte sparsam eingesetzt werden. besonders wenn es Teil der Kernbibliothek von Ruby ist.Ich sage nicht, dass Sie es niemals verwenden sollten, aber es ist normalerweise leicht zu vermeiden und es gibt bessere Optionen, z. B.

class IntegerInString < String

  def initialize( s )
    fail ArgumentError, "The string '#{s}' is not an integer in a string, it's just a string." unless s =~ /^\-?[0-9]+$/
    super
  end
end

Wenn Sie dann eine Zeichenfolge verwenden möchten, die eine Zahl sein könnte, ist klar, was Sie tun, und Sie überlasten keine Kernklasse, z. B.

n = IntegerInString.new "2"
n.to_i
# => 2

IntegerInString.new "blob"
ArgumentError: The string 'blob' is not an integer in a string, it's just a string.

Sie können in der Initialisierung alle möglichen anderen Prüfungen hinzufügen, z. B. die Prüfung auf Binärzahlen usw.Die Hauptsache ist jedoch, dass Ruby für Menschen da ist und es bedeutet, für Menschen zu sein Klarheit.Benennen eines Objekts über seinen Variablennamen Und Sein Klassenname macht Dinge viel klarer.

Ich musste mich in meinem letzten Projekt damit befassen und meine Implementierung war ähnlich, aber etwas anders:

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
someString = "asdfasd123"
number = someString.to_i
if someString != number.to_s
  puts "oops, this isn't a number"
end

Wahrscheinlich nicht der sauberste Weg, aber es sollte funktionieren.

Re: Chris' Antwort

Ihre Implementierung lässt Dinge wie „1a“ oder „b2“ durch.Wie wäre es stattdessen damit:

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

Dies gibt aus:

100
1a is invalid
b2 is invalid
t is invalid
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top