10

I wanted to validate 'numericality' of a string (its not an attribute in an active-record model). I just need it to be a valid base 10, positive integer string. I am doing this:

class String
  def numeric?
    # Check if every character is a digit
    !!self.match(/\A[0-9]+\Z/)
  end
end

class String
  def numeric?
    # Check is there is *any* non-numeric character
    !self.match(/[^0-9]/)
  end
end

Which of these is a more plausible alternative? OR, is there any other better implementation?

4

8 回答 8

10

请确保使用\Aand\Z而不是^and$来匹配整个字符串而不是字符串中的单行。如果要避免将字符串与结束换行符匹配,请在末尾使用 '\z'。有关更多问题,请参阅锚点的正则表达式教程

例如,/^[0-9]+$/成功匹配以下内容:

foo
1234
bar

/\A[0-9]+\Z/没有。

于 2009-08-17T23:38:05.857 回答
5

第一个在我看来是理智的。

不过,我会命名方法numeric?。我不是方法的忠实粉丝is_foo?is_foo它们在方法名称( , )中没有问号的语言中是有意义的isFoo,但是有了问号,is感觉就显得多余了。

于 2009-08-17T09:17:40.837 回答
3

我不是 100% 确定,但 Rails 似乎/\A[+-]?\d+\Z/用于整数。
单击validates_numericality_of 此处显示源

于 2009-08-17T09:50:28.133 回答
2

我建议另一种方法。另外,因为你问的是“正”整数,所以我为正整数和非负整数做了两种不同的方法。

class String
  def numeric?
    !self.match(/[^0-9]/)
  end

  def positive_integer?
    self.to_i > 0
  end

  def nonnegative_integer?
    self.to_i > 0 or self == '0'
  end
end

这是基准代码:

require 'benchmark'
include Benchmark

bmbm(100) do |x|
  x.report('numeric?') do
    "some invalid string".numeric?
  end

  x.report('positive_integer?') do
    "some invalid string".positive_integer?
  end

  x.report('nonnegative_integer?') do
    "some invalid string".nonnegative_integer?
  end
end

结果:

numeric?
0.000000   0.000000   0.000000 (  0.000045)
positive_integer?
0.000000   0.000000   0.000000 (  0.000012)
nonnegative_integer?
0.000000   0.000000   0.000000 (  0.000015)

在这个微基准测试中,它似乎positive_integer?并且更快。nonnegative_integer?

最后,作为旁注,您可以integer?以类似的方式定义方法:

class String
  def integer?
    self.to_i.to_s == self
  end
end
于 2011-04-28T02:32:58.357 回答
1

在非数字字符串的情况下,第二个将更快地完成,因为它将拒绝第一个坏字符。

另外,检查 String#to_i 方法 - 它可能会做你想要的:
http ://www.ruby-doc.org/core/classes/String.html#M000787

于 2009-08-17T09:24:47.420 回答
1

我不知道这是否很快,但我喜欢:

class String
 def numeric?
    true if Integer(object) rescue false
 end
end

也处理负数。如果您将来想支持浮点数,只需使用 Float()

于 2009-08-17T09:35:10.723 回答
0

根据一个简单的基准,第二种方法更快,虽然我不是专家基准,所以这可能不是一个有效的基准: http: //pastie.org/586777

Zalus 的逻辑是正确的。它只需要检查一次无效字符串。

于 2009-08-18T05:53:58.063 回答
0

注意

n = '1234'
n.to_i.to_s == n
=> true

n2 = '1.3'
n.to_i.to_s == n2
=> false

适用于正整数和负整数,但不适用于八进制/十六进制表示、浮点数等。可能不会表现最好(未经测试),但过早的优化不会浪费时间。

于 2012-07-31T00:34:45.503 回答