我的应用程序控制器中有以下内容:
def is_number?(object)
true if Float(object) rescue false
end
以及我的控制器中的以下情况:
if mystring.is_number?
end
该情况导致undefined method
错误。我猜我在错误的地方定义了is_number
......?
答案 0 :(得分:177)
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?
定义为{{1的扩展名类,如:
String
然后你可以用:
来调用它class String
def is_number?
true if Float(self) rescue false
end
end
答案 1 :(得分:29)
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
答案 2 :(得分:26)
以下是解决此问题的常用方法的基准。请注意您应该使用哪一个可能取决于预期的错误案例的比例。
如果表现无关紧要,请使用您喜欢的内容。 : - )
# 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
答案 3 :(得分:14)
依赖引发的异常并不是最快,最可读也不可靠的解决方案 我会做以下事情:
my_string.should =~ /^[0-9]+$/
答案 4 :(得分:6)
不,你只是错误地使用它。你的is_number?有一个论点。你没有参数就叫它
你应该做is_number吗?(mystring)答案 5 :(得分:5)
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
答案 6 :(得分:4)
这就是我这样做的方式,但我认为必须有更好的方法
object.to_i.to_s == object || object.to_f.to_s == object
答案 7 :(得分:4)
在rails 4中,你需要放
require File.expand_path('../../lib', __FILE__) + '/ext/string'
在你的config / application.rb
答案 8 :(得分:3)
如果您不想将异常用作逻辑的一部分,您可以尝试这样做:
class String
def numeric?
!!(self =~ /^-?\d+(\.\d*)?$/)
end
end
或者,如果您希望它适用于所有对象类,请将class String
替换为class Object
将自我转换为字符串:!!(self.to_s =~ /^-?\d+(\.\d*)?$/)
答案 9 :(得分:3)
从Ruby 2.6.0开始,数字转换方法具有可选的exception
参数[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
答案 10 :(得分:0)
由于Kernel#Float,{{3}}可用于验证字符串的数字,我只能添加的是单线版本,而无需使用rescue
块来控制流(有时被认为是不好的做法)
Float(my_string, exception: false).present?
答案 11 :(得分:-2)
使用以下功能:
def is_numeric? val
return val.try(:to_f).try(:to_s) == val
end
所以,
is_numeric? "1.2f"
= false
is_numeric? "1.2"
= true
is_numeric? "12f"
= false
is_numeric? "12"
= true
答案 12 :(得分:-5)
这个解决方案多么愚蠢?
def is_number?(i)
begin
i+0 == i
rescue TypeError
false
end
end