Реализация Ruby is_numeric? для строк, нужны лучшие альтернативы

Я хотел проверить "численность" строки (ее не атрибут в модели с активной записью). Мне просто нужно, чтобы она была действительной базой 10, положительной целой строкой. Я делаю это:

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

Какая из них является более правдоподобной альтернативой? ИЛИ, есть ли другая лучшая реализация?

Ответ 1

Пожалуйста, используйте \A и \Z, а не ^ и $, чтобы соответствовать всей строке, а не только одной строке строки. Если вы хотите избежать совпадения строки с конечной новой строкой, используйте '\ z' в конце. Дополнительные сведения см. В Учебное пособие по привязкам.

Например, /^[0-9]+$/ успешно соответствует следующему:

foo
1234
bar

но /\A[0-9]+\Z/ не работает.

Ответ 2

Первый выглядит для меня здоровым.

Я бы назвал метод numeric?. Я не большой поклонник методов is_foo?. Они имеют смысл в языках, которые не имеют вопросительных знаков в именах методов (is_foo, isFoo), но с вопросительным знаком is чувствует себя излишним.

Ответ 3

Я не уверен на 100%, но Rails, похоже, использует /\A[+-]?\d+\Z/ для целых чисел.
Нажмите здесь, чтобы показать источник validates_numericality_of здесь

Ответ 4

Я бы предложил другой способ сделать это. Кроме того, поскольку вы задали "положительное" целое число, я сделал два отдельных метода для положительного целого и неотрицательного целого числа.

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

Ответ 5

Второй будет быстрее завершен в случае нечисловой строки, поскольку он отклонит первый плохой символ.

Также проверьте метод String # to_i - он, возможно, делает то, что вы хотите:
http://www.ruby-doc.org/core/classes/String.html#M000787

Ответ 6

Я не знаю, скоро ли это, но мне нравится:

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

Также обрабатывает отрицательные числа. И если вы когда-нибудь захотите поддерживать плавания в будущем, просто используйте Float()

Ответ 7

В соответствии с простым эталоном второй подход выполняется быстрее, хотя я не являюсь экспертным контрольным маркером, поэтому это может оказаться недействительным. http://pastie.org/586777

Логика Залуса правильная. Это нужно только один раз проверить для недействительной строки.

Ответ 8

Примечание

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

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

работает с целыми положительными и отрицательными целыми числами, но не с восьмеричными представлениями, поплавками и т.д. Может не выполнять лучших (непроверенных), но не тратить время на то, чтобы избежать преждевременных оптимизаций.