アプリケーションコントローラーに次のものがあります。
def is_number?(object)
true if Float(object) rescue false
end
そして、私のコントローラーの次の状態:
if mystring.is_number?
end
条件はundefined method
エラーをスローしています。is_number
間違った場所で定義したと思います...?
アプリケーションコントローラーに次のものがあります。
def is_number?(object)
true if Float(object) rescue false
end
そして、私のコントローラーの次の状態:
if mystring.is_number?
end
条件はundefined method
エラーをスローしています。is_number
間違った場所で定義したと思います...?
回答:
is_number?
メソッドを作成します。ヘルパーメソッドを作成します。
def is_number? string
true if Float(string) rescue false
end
そして、次のように呼び出します。
my_string = '12.34'
is_number?( my_string )
# => true
String
クラスを拡張します。is_number?
ヘルパー関数にパラメーターとして渡すのではなく、文字列を直接呼び出すことができるようにしたい場合は、次のようにクラスのis_number?
拡張として定義する必要がありますString
。
class String
def is_number?
true if Float(self) rescue false
end
end
そして、あなたはそれを次のように呼び出すことができます:
my_string.is_number?
# => true
to_f
上記には何もなく、Float()はその動作を示しません。Float("330.346.11")
レイズArgumentError: invalid value for Float(): "330.346.11"
lib/core_ext/string.rb
。
is_number?(string)
ビットはRuby 1.9では動作しないと思います。多分それはRailsまたは1.8の一部ですか? String.is_a?(Numeric)
動作します。stackoverflow.com/questions/2095493/…も参照してください。
この問題に対処する一般的な方法のベンチマークは次のとおりです。どちらを使用する必要があるかは、おそらく予想される誤ったケースの比率に依存することに注意してください。
パフォーマンスが問題ではない場合は、好きなものを使用してください。:-)
# 1.9.3-p448
#
# Calculating -------------------------------------
# cast 57485 i/100ms
# cast fail 5549 i/100ms
# to_s 47509 i/100ms
# to_s fail 50573 i/100ms
# regexp 45187 i/100ms
# regexp fail 42566 i/100ms
# -------------------------------------------------
# cast 2353703.4 (±4.9%) i/s - 11726940 in 4.998270s
# cast fail 65590.2 (±4.6%) i/s - 327391 in 5.003511s
# to_s 1420892.0 (±6.8%) i/s - 7078841 in 5.011462s
# to_s fail 1717948.8 (±6.0%) i/s - 8546837 in 4.998672s
# regexp 1525729.9 (±7.0%) i/s - 7591416 in 5.007105s
# regexp fail 1154461.1 (±5.5%) i/s - 5788976 in 5.035311s
require 'benchmark/ips'
int = '220000'
bad_int = '22.to.2'
Benchmark.ips do |x|
x.report('cast') do
Integer(int) rescue false
end
x.report('cast fail') do
Integer(bad_int) rescue false
end
x.report('to_s') do
int.to_i.to_s == int
end
x.report('to_s fail') do
bad_int.to_i.to_s == bad_int
end
x.report('regexp') do
int =~ /^\d+$/
end
x.report('regexp fail') do
bad_int =~ /^\d+$/
end
end
# 1.9.3-p448
#
# Calculating -------------------------------------
# cast 47430 i/100ms
# cast fail 5023 i/100ms
# to_s 27435 i/100ms
# to_s fail 29609 i/100ms
# regexp 37620 i/100ms
# regexp fail 32557 i/100ms
# -------------------------------------------------
# cast 2283762.5 (±6.8%) i/s - 11383200 in 5.012934s
# cast fail 63108.8 (±6.7%) i/s - 316449 in 5.038518s
# to_s 593069.3 (±8.8%) i/s - 2962980 in 5.042459s
# to_s fail 857217.1 (±10.0%) i/s - 4263696 in 5.033024s
# regexp 1383194.8 (±6.7%) i/s - 6884460 in 5.008275s
# regexp fail 723390.2 (±5.8%) i/s - 3613827 in 5.016494s
require 'benchmark/ips'
float = '12.2312'
bad_float = '22.to.2'
Benchmark.ips do |x|
x.report('cast') do
Float(float) rescue false
end
x.report('cast fail') do
Float(bad_float) rescue false
end
x.report('to_s') do
float.to_f.to_s == float
end
x.report('to_s fail') do
bad_float.to_f.to_s == bad_float
end
x.report('regexp') do
float =~ /^[-+]?[0-9]*\.?[0-9]+$/
end
x.report('regexp fail') do
bad_float =~ /^[-+]?[0-9]*\.?[0-9]+$/
end
end
class String
def numeric?
return true if self =~ /\A\d+\Z/
true if Float(self) rescue false
end
end
p "1".numeric? # => true
p "1.2".numeric? # => true
p "5.4e-29".numeric? # => true
p "12e20".numeric? # true
p "1a".numeric? # => false
p "1.2.3.4".numeric? # => false
/^\d+$/
Rubyでは安全な正規表現ではありません/\A\d+\Z/
。(たとえば、「42 \ n何かのテキスト」はを返しますtrue
)
/^\d+$/
ラインを扱う場合は、このケースでは、このように、文字列の先頭と末尾についてです/\A\d+\Z/
。
発生した例外に依存することは、最速で、読みやすく、信頼できるソリューションではありません。
私は次のようにします:
my_string.should =~ /^[0-9]+$/
expect(my_string).to match(/^[0-9]+$/)
my_string =~ /\A-?(\d+)?\.?\d+\Z/
「.1」、「-0.1」、または「12」を実行できますが、「」、「-」、「。」は実行できません。
Ruby 2.6.0以降、数値キャストメソッドにはオプションのexception
-argument [1]があります。これにより、制御フローとして例外を使用せずに組み込みメソッドを使用できるようになります。
Float('x') # => ArgumentError (invalid value for Float(): "x")
Float('x', exception: false) # => nil
したがって、独自のメソッドを定義する必要はありませんが、次のような変数を直接チェックできます。
if Float(my_var, exception: false)
# do something if my_var is a float
end
これが私のやり方ですが、私ももっと良い方法があるはずだと思います
object.to_i.to_s == object || object.to_f.to_s == object
object = "1.2e+35"; object.to_f.to_s == object
したところ、うまくいきました
いいえ、間違って使用しています。あなたのis_number?議論があります。引数なしで呼び出しました
is_numberを実行する必要がありますか?(mystring)
mystring
が実際に文字列の場合、mystring.is_a?(Integer)
常にfalseになります。彼は次のような結果を望んでいるようですis_number?("12.4") #=> true
Tl; dr:正規表現アプローチを使用します。承認された回答のレスキューアプローチより39倍高速で、「1,000」のようなケースも処理します
def regex_is_number? string
no_commas = string.gsub(',', '')
matches = no_commas.match(/-?\d+(?:\.\d+)?/)
if !matches.nil? && matches.size == 1 && matches[0] == no_commas
true
else
false
end
end
-
@Jakob Sが受け入れた回答はほとんどの場合機能しますが、例外のキャッチは非常に遅くなる可能性があります。さらに、レスキューアプローチは、「1,000」のような文字列では失敗します。
メソッドを定義しましょう:
def rescue_is_number? string
true if Float(string) rescue false
end
def regex_is_number? string
no_commas = string.gsub(',', '')
matches = no_commas.match(/-?\d+(?:\.\d+)?/)
if !matches.nil? && matches.size == 1 && matches[0] == no_commas
true
else
false
end
end
そして今いくつかのテストケース:
test_cases = {
true => ["5.5", "23", "-123", "1,234,123"],
false => ["hello", "99designs", "(123)456-7890"]
}
そして、テストケースを実行するための小さなコード:
test_cases.each do |expected_answer, cases|
cases.each do |test_case|
if rescue_is_number?(test_case) != expected_answer
puts "**rescue_is_number? got #{test_case} wrong**"
else
puts "rescue_is_number? got #{test_case} right"
end
if regex_is_number?(test_case) != expected_answer
puts "**regex_is_number? got #{test_case} wrong**"
else
puts "regex_is_number? got #{test_case} right"
end
end
end
テストケースの出力は次のとおりです。
rescue_is_number? got 5.5 right
regex_is_number? got 5.5 right
rescue_is_number? got 23 right
regex_is_number? got 23 right
rescue_is_number? got -123 right
regex_is_number? got -123 right
**rescue_is_number? got 1,234,123 wrong**
regex_is_number? got 1,234,123 right
rescue_is_number? got hello right
regex_is_number? got hello right
rescue_is_number? got 99designs right
regex_is_number? got 99designs right
rescue_is_number? got (123)456-7890 right
regex_is_number? got (123)456-7890 right
パフォーマンスベンチマークを行う時間:
Benchmark.ips do |x|
x.report("rescue") { test_cases.values.flatten.each { |c| rescue_is_number? c } }
x.report("regex") { test_cases.values.flatten.each { |c| regex_is_number? c } }
x.compare!
end
そして結果:
Calculating -------------------------------------
rescue 128.000 i/100ms
regex 4.649k i/100ms
-------------------------------------------------
rescue 1.348k (±16.8%) i/s - 6.656k
regex 52.113k (± 7.8%) i/s - 260.344k
Comparison:
regex: 52113.3 i/s
rescue: 1347.5 i/s - 38.67x slower
5.4e-29
ます。私はあなたの正規表現がそれらも受け入れるように調整されると思います。
Rails 4ではrequire File.expand_path('../../lib', __FILE__) + '/ext/string'
、config / application.rb を配置する必要があり
ます
ロジックの一部として例外を使用したくない場合は、これを試すことができます。
class String
def numeric?
!!(self =~ /^-?\d+(\.\d*)?$/)
end
end
それとも、あなたはすべてのオブジェクトクラス全体で仕事にそれをしたい場合は、交換するclass String
とclass Object
文字列に変換する自己: !!(self.to_s =~ /^-?\d+(\.\d*)?$/)
nil?
ゼロにすることの目的はルビーでは不法なので、あなたはちょうど行うことができます!!(self =~ /^-?\d+(\.\d*)?$/)
!!
確かに使用できます。少なくとも1つのRubyスタイルガイド(github.com/bbatsov/ruby-style-guide)!!
は.nil?
、読みやすさを優先して回避することを提案してい!!
ますが、人気のあるリポジトリで使用されているのを見たことがあり、ブール値に変換するための素晴らしい方法だと思います。回答を編集しました。
次の関数を使用します。
def is_numeric? val
return val.try(:to_f).try(:to_s) == val
end
そう、
is_numeric? "1.2f"
= false
is_numeric? "1.2"
=真
is_numeric? "12f"
= false
is_numeric? "12"
=真
"0"
ます。また、このメソッド.try
はRubyコアライブラリの一部ではなく、ActiveSupportが含まれている場合にのみ使用できることにも注意してください。
"12"
ので、この質問の4番目の例は間違っています。"12.10"
そして"12.00"
失敗も。
このソリューションはどれほど馬鹿げていますか?
def is_number?(i)
begin
i+0 == i
rescue TypeError
false
end
end