测试string在Ruby on Rails中是否为数字

| 我的应用程序控制器中有以下内容:
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
扩展“ 7”级。 如果希望直接在字符串上调用call4ѭ,而不是将其作为参数传递给助手函数,则需要将then4ѭ定义为
String
类的扩展,如下所示:
class String
  def is_number?
    true if Float(self) rescue false
  end
end
然后可以使用以下命令调用它:
my_string.is_number?
# => true
    
这是解决此问题的常用方法的基准。请注意,应该使用哪一种可能取决于预期的错误案例比率。 如果它们相对不常见,铸造绝对是最快的。 如果错误的情况很普遍,而您只是检查整数,那么比较与转换状态是一个不错的选择。 如果错误的情况很常见,并且您正在检查浮点数,则可以使用regexp 如果性能无关紧要,请使用您喜欢的东西。 :-) 整数检查详细信息:
# 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
    
依靠引发的异常并不是最快,可读性也不可靠的解决方案。 我将执行以下操作:
my_string.should =~ /^[0-9]+$/
    
不,您只是在错误地使用它。您的is_number?有一个论点。你不带参数就叫它 你应该在做is_number吗?(mystring)     
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
    
这就是我的方法,但我认为也必须有更好的方法
object.to_i.to_s == object || object.to_f.to_s == object
    
在rails 4中,您需要放置
require File.expand_path(\'../../lib\', __FILE__) + \'/ext/string\'
在你的config / application.rb中     
从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
    
如果您不希望将异常用作逻辑的一部分,则可以尝试以下操作:
class String
   def numeric?
    !!(self =~ /^-?\\d+(\\.\\d*)?$/)
  end
end
或者,如果您希望它在所有对象类中都适用,请将
class String
替换为
class Object
,并将其转换为字符串:
!!(self.to_s =~ /^-?\\d+(\\.\\d*)?$/)
    
使用以下功能:
def is_numeric? val
    return val.try(:to_f).try(:to_s) == val
end
所以,
is_numeric? \"1.2f\"
=否
is_numeric? \"1.2\"
=真
is_numeric? \"12f\"
=否
is_numeric? \"12\"
=真     
这个解决方案有多愚蠢?
def is_number?(i)
  begin
    i+0 == i
  rescue TypeError
    false
  end
end
    

要回复问题请先登录注册