Реализация 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

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

8 ответов

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

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

foo
1234
bar

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


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

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


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


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

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


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

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

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


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

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


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

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


Примечание

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

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

licensed under cc by-sa 3.0 with attribution.