166

たとえば、文字列があり、'123'それを整数に変換したいと考えてい123ます。

単純に を実行できることはわかっていますが、それはsome_string.to_iに変換'lolipops'0れます。これは、私が考えている効果ではありません。無効なものを変換しようとすると、素敵で痛いException. 0そうしないと、有効な数値と数値ではない数値を区別できません。

編集:正規表現のトリックなしで、標準的な方法を探していました。

4

8 に答える 8

240

Ruby には次の機能が組み込まれています。

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

Joseph Pecoraroの回答に記載されているように0x、16 進数や2 進数で始まる文字列など、10 進数以外の有効な文字列や0b、8 進数として解析されるゼロで始まる可能性のあるよりトリッキーな数値を監視する必要がある場合があります。

Ruby 1.9.2 では基数のオプションの 2 番目の引数が追加されたため、上記の問題を回避できます。

Integer('23')                                     # => 23
Integer('0x23')                                   # => 35
Integer('023')                                    # => 19
Integer('0x23', 10)
# => #<ArgumentError: invalid value for Integer: "0x23">
Integer('023', 10)                                # => 23
于 2008-09-08T07:49:16.170 に答える
31

これはうまくいくかもしれません:

i.to_i if i.match(/^\d+$/)
于 2008-09-08T07:49:27.650 に答える
25

また、現在受け入れられている解決策が 16 進数、8 進数、および 2 進数の解析に与える影響にも注意してください。

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

0xまたはで始まる Ruby の数値0Xは、16 進数、0bまたは0B2 進数で、08 進数のみです。これが望ましい動作でない場合は、最初に文字列がパターンに一致するかどうかを確認する他のソリューションと組み合わせることができます。/\d+/正規表現などのように。

于 2008-09-10T03:11:17.333 に答える
17

受け入れられたソリューションでの別の予期しない動作 (1.8、1.9 では問題ありません):

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

そのため、何が渡されているかわからない場合は、必ず.to_s.

于 2010-03-31T10:14:51.783 に答える
9

Myron の回答は気に入っていますが、 「Java/C# を使用しなくなったので、継承を二度と使用しない」という Ruby 病に苦しんでいます。クラスを開くことは危険を伴う可能性があるため、慎重に使用する必要があります。特に、それが Ruby のコア ライブラリの一部である場合は注意が必要です。決して使用しないと言っているわけではありませんが、通常は簡単に回避でき、より良いオプションが利用可能です。

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

次に、数値である可能性のある文字列を使用したい場合、何をしているのかが明確であり、コアクラスを壊しません。

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.

2 進数のチェックなど、あらゆる種類の他のチェックを初期化に追加できます。ただし、主なことは、Ruby は人のためのものであり、人のためであるということは明快さを意味するということです。変数名とクラス名を使用してオブジェクトに名前を付けると、物事がより明確になります。

于 2013-05-13T16:32:40.130 に答える
7

前回のプロジェクトでこれに対処する必要がありました。実装は似ていましたが、少し異なります。

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
于 2008-09-25T06:27:33.500 に答える
3
someString = "asdfasd123"
number = someString.to_i
if someString != number.to_s
  puts "oops, this isn't a number"
end

おそらく最もクリーンな方法ではありませんが、うまくいくはずです。

于 2008-09-08T07:52:28.207 に答える
1

Re:クリスの答え

あなたの実装では、「1a」や「b2」などを実行してみましょう。代わりにこれはどうですか:

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

これは以下を出力します:

100
1a is invalid
b2 is invalid
t is invalid
于 2008-09-10T12:04:21.827 に答える