1

可能重复:
在 Ruby on Rails 中测试字符串是否为数字

目前我有这个(可怕的)代码:

def is_num(num_given)
  begin
    num_given.to_i
    worked = true
  rescue
    worked = false
  ensure
    return worked
  end
end

我对此进行了重构:

def is_num(num_given)
  num_given.to_i.is_a?(Numeric) rescue false
end

这对我来说仍然感觉不对,有更好的方法吗?

这两种实现都适合我的目的,我只是在寻找一些代码兴奋。

4

4 回答 4

2

something.is_a?(Numeric)是要走的路。参考您的后一个示例,无需调用to_i输入。

请注意,something.is_a?(Numeric)如果您要查看字符串是否为数字,这将不起作用...

于 2012-10-31T00:25:55.543 回答
2

这是另一个解决方案。它不是很像 Ruby,但这是故意的(例如,whilestr.chars.each这种情况下要快)。

# is a character between 0 and 9? (based on C's isdigit())
def digit?(c)
  o = c.ord
  o >= 48 && o <= 57 # '0'.ord, '9'.ord
end

# is a string numeric (i.e., represented as an integer or decimal)?
def numeric?(str)
  str = str.to_s unless str.is_a?(String)
  l = str.length
  i = 0

  while i < l
    c = str[i]
    if c == '.' || c == '-'
      i += 1
      next
    end

    return false if !digit?(c)

    i += 1
  end

  true
end

这是单元测试。如果我错过了一个案例,请告诉我。对于其他回答者,只需将subject块更改为您的功能。

if $0 == __FILE__
  require 'minitest/autorun'
  describe :digit? do
    %w(- + : ? ! / \ ! @ $ ^ & *).each do |c|
      it "flunks #{c}" do
        digit?(c).must_equal false
      end
    end

    %w(0 1 2 3 4 5 6 7 8 9).each do |c|
      it "passes #{c}" do
        digit?(c).must_equal true
      end
    end
  end

  describe :numeric? do
    subject { :numeric? }
    %w(0 1 9 10 18 123.4567 -1234).each do |str|
      it "passes #{str}" do
        method(subject).call(str).must_equal true
      end
    end

    %w(-asdf 123.zzz blah).each do |str|
      it "flunks #{str}" do
        method(subject).call(str).must_equal false
      end
    end

    [-1.03, 123, 200_000].each do |num|
      it "passes #{num}" do
        method(subject).call(num).must_equal true
      end
    end
  end
end
于 2012-10-31T00:48:21.327 回答
1

您列出的功能不起作用:

is_num("a") #=> true

问题是它们不会为无效输入引发错误。你想要的是Integer,这会引发一个你可以挽救的错误:

def is_num(num_given)
  !!Integer(num_given) rescue false
end

这有效:

irb(main):025:0> is_num("a")
=> false
irb(main):026:0> is_num(5)
=> true
irb(main):027:0> is_num((1..2))
=> false
irb(main):028:0> is_num("3")
=> true

(不过,可能有更自然的方法来做到这一点。)

于 2012-10-30T23:47:46.427 回答
0

您始终可以使用简单的正则表达式:

def is_num(num_given)
  num_given =~ /\d+(\.\d+)?/
end
于 2012-10-30T23:43:29.873 回答