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
这是解决这个问题的常用方法的基准。 注意你应该使用哪一个,可能取决于预期的假情况的比例。
- 如果他们比较less见的话,铸造肯定是最快的。
- 如果错误的情况是常见的,你只是检查整数,比较与转换后的状态是一个不错的select。
- 如果错误的情况是常见的,你正在检查浮动,正则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 String
replace为一个将自身转换为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