testingstring是否是Ruby on Rails中的一个数字

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

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

和我的控制器中的以下情况:

 if mystring.is_number? end 

该条件是抛出undefined method错误。 我猜我已经在错误的地方定义了is_number …?

创buildis_number? 方法。

创build一个帮手方法:

 def is_number? string true if Float(string) rescue false end 

然后像这样调用它:

 my_string = '12.34' is_number?( my_string ) # => true 

扩展String类。

如果你想能够打电话给is_number? 直接在string上,而不是作为parameter passing给你的帮助函数,那么你需要定义is_number? 作为String类的扩展,如下所示:

 class String def is_number? true if Float(self) rescue false end end 

然后你可以调用它:

 my_string.is_number? # => true 
 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 

这是解决这个问题的常用方法的基准。 注意你应该使用哪一个,可能取决于预期的假情况的比例。

  1. 如果他们比较less见的话,铸造肯定是最快的。
  2. 如果错误的情况是常见的,你只是检查整数,比较与转换后的状态是一个不错的select。
  3. 如果错误的情况是常见的,你正在检查浮动,正则expression式可能是要走的路

如果性能无关紧要,用你喜欢的东西。 🙂

整数检查细节:

 # 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 

依靠提出的例外不是最快,可读,也不可靠的解决scheme。
我会做以下几点:

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

不,你只是用错了。 你的号码? 有一个说法。 你没有理由就这么称呼它

你应该做is_number?(mystring)

这是我如何做到的,但是我认为也必须有更好的办法

 object.to_i.to_s == object || object.to_f.to_s == object 

在rails 4中,你需要在你的config / application.rb中放置require File.expand_path('../../lib', __FILE__) + '/ext/string'

T1;博士:使用正则expression式的方法。 在接受的答案中,它比救援方法快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接受的答案大部分都适用,但捕获exception可能非常缓慢。 另外,救援方法失败的string如“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 

现在一些testing用例:

 test_cases = { true => ["5.5", "23", "-123", "1,234,123"], false => ["hello", "99designs", "(123)456-7890"] } 

还有一些运行testing用例的代码:

 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 

这里是testing用例的输出:

 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.649ki/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 

如果你不想把exception作为逻辑的一部分,你可以试试这个:

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

或者,如果您希望它可以跨所有对象类使用,请将class Stringreplace为一个将自身转换为string的类: !!(self.to_s =~ /^-?\d+(\.\d*)?$/)

使用以下function:

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

所以,

is_numeric? "1.2f" is_numeric? "1.2f" = false

is_numeric? "1.2" is_numeric? "1.2" = true

is_numeric? "12f" is_numeric? "12f" = false

is_numeric? "12" is_numeric? "12" = true

这个解决scheme有多愚蠢?

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