回答:
Rubyにはこの機能が組み込まれています。
Integer('1001') # => 1001
Integer('1001 nights')
# ArgumentError: invalid value for Integer: "1001 nights"
Joseph Pecoraroの回答で述べたように0x
、16進数と0b
2 進数で始まるものなど、有効な非10進数の文字列や、0で始まる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
これはうまくいくかもしれません:
i.to_i if i.match(/^\d+$/)
\z
の代わりに\Z
大文字のZアンカーの記述があるとして: - 「マッチは文字列の末尾の改行を含む文字列が終了した場合、それだけで改行の前にマッチします。」ruby-doc.org/core-2.1.1/Regexp .html
また、現在受け入れられているソリューションが16進数、8進数、2進数の解析に与える影響にも注意してください。
>> Integer('0x15')
# => 21
>> Integer('0b10')
# => 2
>> Integer('077')
# => 63
始まるRubyの番号で0x
または0X
進をしている、0b
または0B
単にバイナリであり、0
オクタルです。これが望ましい動作ではない場合は、最初に文字列がパターンに一致するかどうかをチェックする他のいくつかのソリューションと組み合わせることができます。同様に/\d+/
、正規表現など
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は人のためであり、人のためになることは明確さを意味するということです。変数名とクラス名を使用してオブジェクトに名前を付けると、状況がわかりやすくなります。
私は最後のプロジェクトでこれに対処する必要があり、私の実装は似ていますが、少し異なります:
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
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
\z
の代わりに\Z
大文字のZアンカーの記述があるとして: - 「マッチは文字列の末尾の改行を含む文字列が終了した場合、それだけで改行の前にマッチします。」ruby-doc.org/core-2.1.1/Regexp .html
^
と$
微妙に異なる意味を持っています。あなたは、おそらく使用することを意味\A
し、\Z
代わりに。