Ruby on rails 在RubyonRails中测试字符串是否为数字

Ruby on rails 在RubyonRails中测试字符串是否为数字,ruby-on-rails,ruby,string,integer,Ruby On Rails,Ruby,String,Integer,我的应用程序控制器中有以下内容: def is_number?(object) true if Float(object) rescue false end if mystring.is_number? end 以及控制器中的以下情况: def is_number?(object) true if Float(object) rescue false end if mystring.is_number? end 该条件正在抛出一个未定义的方法错误。我猜我定义的是不是在错误的地

我的应用程序控制器中有以下内容:

def is_number?(object)
  true if Float(object) rescue false
end
if mystring.is_number?

end
以及控制器中的以下情况:

def is_number?(object)
  true if Float(object) rescue false
end
if mystring.is_number?

end

该条件正在抛出一个
未定义的方法
错误。我猜我定义的
是不是在错误的地方…?

不,你只是用错了。你的电话号码是多少?他有一个论点。你没有辩论就说了


你应该做的是什么?(mystring)

我就是这样做的,但我认为一定有更好的方法

object.to_i.to_s == object || object.to_f.to_s == object
创建
is\u number?
方法。 创建助手方法:

def is_number? string
  true if Float(string) rescue false
end
然后这样称呼它:

my_string = '12.34'

is_number?( my_string )
# => true
扩展
字符串
类。 如果希望能够直接在字符串上调用
is\u number?
,而不是将其作为参数传递给助手函数,则需要将
is\u number?
定义为
string
类的扩展,如下所示:

class String
  def is_number?
    true if Float(self) rescue false
  end
end
然后你可以用以下方式来称呼它:

my_string.is_number?
# => true

依赖引发的异常不是最快、可读性和可靠性的解决方案。
我会做以下几件事:

my_string.should =~ /^[0-9]+$/

如果您不希望将异常作为逻辑的一部分,可以尝试以下方法:

class String
   def numeric?
    !!(self =~ /^-?\d+(\.\d*)?$/)
  end
end

或者,如果您希望它能够跨所有对象类工作,请将
类字符串
替换为
类对象
转换为字符串:
!!(self.to_s=~/^-?\d+(\.\d*)?$/)

这个解决方案有多愚蠢

def is_number?(i)
  begin
    i+0 == i
  rescue TypeError
    false
  end
end

以下是解决此问题的常用方法的基准。请注意,您应该使用哪一种可能取决于预期的错误案例的比率

  • 如果他们是相对不常见的铸造肯定是最快的
  • 如果错误情况很常见,并且您只是在检查int,那么比较与转换状态是一个不错的选择
  • 如果错误的情况很常见,并且您正在检查浮动,那么regexp可能是一种方法
  • 如果性能不重要,请使用您喜欢的工具。:-)

    整数检查详细信息: 浮动检查详细信息:
    在rails 4中,您需要
    require File.expand_path('../../lib',uuu File++'/ext/string'

    在config/application.rb中使用以下函数:

    def is_numeric? val
        return val.try(:to_f).try(:to_s) == val
    end
    
    所以

    是数字吗?“1.2f”
    =错误

    是数字吗?“1.2”
    =真

    是数字吗?“12f”
    =错误


    是数字吗?“12”
    =true

    Tl;dr:使用正则表达式方法。在公认的答案中,它比救援方法快39倍,还可以处理“1000”之类的情况

    --

    @Jakob S接受的答案在很大程度上是有效的,但是捕获异常的速度可能非常慢。此外,救援方法在“1000”这样的字符串上失败

    让我们定义方法:

    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
    
    还有一些运行测试用例的代码:

    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
    
    以下是测试用例的输出:

    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
    

    从Ruby 2.6.0开始,数值转换方法有一个可选的
    exception
    -参数。这使我们能够使用内置方法,而不使用异常作为控制流:

    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
    
    因为,可以用来验证字符串的数字性,所以我唯一可以添加的是它的一个线性版本,而不使用
    rescue
    块来控制流(这有时被认为是一种不好的做法)

    Float(我的字符串,异常:false)。是否存在?
    

    基于is\U编号?问题中的方法,使用is_a?没有给出正确的答案。如果
    mystring
    确实是一个字符串,
    mystring.is_a?(整数)
    将始终为false。看起来他想要的结果是
    is_number?(“12.4”)=>true
    Jakob S是正确的。mystring实际上总是一个字符串,但可能只是由数字组成。也许我的问题应该是数字?为了避免混淆数据类型,这只适用于正整数。“-1”、“0.0”或“1_000”等值都返回false,即使它们是有效的数值。您看到的是类似于/^[-.0-9]+$/,但它错误地接受了“--”。来自Rails的“验证了:raw_value.to_s=~/\A[+-]?\d+\Z/NoMethodError:undefined method`should'”:string在最新的rspec中,它变成了
    expect(my_string)。要匹配(/^[0-9]+$/)
    I like:
    my_string=~/\A+(\d-)?\。?\d+\Z/
    它允许您执行“.1”、“-0.1”或“12”,但不允许执行“、-”或“.”这是个坏主意。“330.346.11.”to#f=>330.346上面没有
    to#f
    ,Float()不会表现出这种行为:
    Float(“330.346.11”)
    引发
    ArgumentError:Float()的值无效:“330.346.11”
    如果使用该补丁,我会将其重命名为numeric?,以符合ruby命名约定(数值类继承自Numeric,is.\ux前缀是javaish)。这与最初的问题不太相关,但我可能会将代码放在
    lib/core\u ext/string.rb
    中。我不认为
    是数值?(string)
    位工作于Ruby 1.9。也许这是Rails或1.8的一部分?
    string。是吗?(数值)
    有效。另请参见。它不识别浮点表示法,例如1.2e+35。在Ruby 2.4.0中,我运行了
    object=“1.2e+35”;object.to_f.to_s==object
    而且它能工作我知道很多人来这里是因为codeschool的Rails for Zombies测试课。只要等他继续解释。测试不应该通过——让你测试出错是可以的,你总是可以修补Rails来发明诸如self之类的方法。你知道吗?公认的答案是失败的像“1000”这样的情况比使用正则表达式慢39倍。请参见下面的答案。这是次优的,因为使用“.respond_to”(:+)”总是比在特定方法上失败并捕获异常要好(:+)这也可能会失败,原因有很多,比如正则表达式和转换方法没有。实际上你不需要这样做,你可以把string.rb放在“initializers”中,然后