たとえば、文字列があり、'123'
それを整数に変換したいと考えてい123
ます。
単純に を実行できることはわかっていますが、それはsome_string.to_i
に変換'lolipops'
さ0
れます。これは、私が考えている効果ではありません。無効なものを変換しようとすると、素敵で痛いException
. 0
そうしないと、有効な数値と数値ではない数値を区別できません。
編集:正規表現のトリックなしで、標準的な方法を探していました。
たとえば、文字列があり、'123'
それを整数に変換したいと考えてい123
ます。
単純に を実行できることはわかっていますが、それはsome_string.to_i
に変換'lolipops'
さ0
れます。これは、私が考えている効果ではありません。無効なものを変換しようとすると、素敵で痛いException
. 0
そうしないと、有効な数値と数値ではない数値を区別できません。
編集:正規表現のトリックなしで、標準的な方法を探していました。
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
これはうまくいくかもしれません:
i.to_i if i.match(/^\d+$/)
また、現在受け入れられている解決策が 16 進数、8 進数、および 2 進数の解析に与える影響にも注意してください。
>> Integer('0x15')
# => 21
>> Integer('0b10')
# => 2
>> Integer('077')
# => 63
0x
またはで始まる Ruby の数値0X
は、16 進数、0b
または0B
2 進数で、0
8 進数のみです。これが望ましい動作でない場合は、最初に文字列がパターンに一致するかどうかを確認する他のソリューションと組み合わせることができます。/\d+/
正規表現などのように。
受け入れられたソリューションでの別の予期しない動作 (1.8、1.9 では問題ありません):
>> Integer(:foobar)
=> 26017
>> Integer(:yikes)
=> 26025
そのため、何が渡されているかわからない場合は、必ず.to_s
.
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
someString = "asdfasd123"
number = someString.to_i
if someString != number.to_s
puts "oops, this isn't a number"
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