Question

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?

Was it helpful?

Solution

Please make sure use \A and \Z rather than ^ and $, to match the entire string rather than just a single line in the string. If you want to avoid matching a string with an ending newline, use '\z' at the end. For more issues, see The Regex Tutorial on anchors.

For example, /^[0-9]+$/ successfully matches the following:

foo
1234
bar

but /\A[0-9]+\Z/ does not.

OTHER TIPS

The first one looks sane to me.

I'd name the method numeric?, though. I'm not a big fan of is_foo? methods. They make sense in languages that doesn't have question marks in method names (is_foo, isFoo), but with the question mark, the is feels redundant.

I'm not a 100% certain but Rails seems to be using /\A[+-]?\d+\Z/ for integers.
Click on show source for validates_numericality_of here

I'd suggest another way of doing it. Also, because you asked "positive" integer, I made two separate methods for positive integer and non-negative integer.

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

Here's the benchmark code:

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

Result:

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)

It seems like positive_integer? and nonnegative_integer? are faster in this micro-benchmark.

Finally, as a side note, you can define integer? method in a similar fashion:

class String
  def integer?
    self.to_i.to_s == self
  end
end

The second will finish quicker in the case of a non-numeric string, as it will reject on the first bad character.

Also, check out the String#to_i method - it possibly does what you want:
http://www.ruby-doc.org/core/classes/String.html#M000787

I dont know if this is fast, but I like:

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

Handles negative numbers as well. And if you ever wanted to support floats in the future, just use Float()

According to a simple benchmark, the second approach is faster, although I'm not expert benchmarker, so this might not be a valid benchmark: http://pastie.org/586777

Zalus' logic is right. It only needs to check once for a non-valid string.

Notice

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

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

works for positive & negative integers, but not octal/hex representations, floats etc. May not perform the best (untested), but no point wasting time with premature optimizations.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top