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

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


person Swanand    schedule 17.08.2009    source источник
comment
Из любопытства, почему множитель {1,1}? По умолчанию все классы символов и литералы сопоставляются ровно один раз, если не указано иное. Это избыточно.   -  person Matthew Scharley    schedule 17.08.2009
comment
Бедный я! Сниму сразу.   -  person Swanand    schedule 17.08.2009
comment
Связанный вопрос: stackoverflow.com/questions/694176/   -  person Andrew Grimm    schedule 28.04.2011


Ответы (8)


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

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

foo
1234
bar

но /\A[0-9]+\Z/ этого не делает.

person Bkkbrad    schedule 17.08.2009

Первый мне кажется нормальным.

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

person August Lilleaas    schedule 17.08.2009
comment
В итоге я использовал второй. - person Swanand; 24.08.2009

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

person Gishu    schedule 17.08.2009
comment
\ A - ›Начало строки \ Z -› Конец строки В основном то же самое, что и в первом, за исключением положительной / отрицательной части модификатора. - person Swanand; 17.08.2009

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

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
person kenn    schedule 28.04.2011

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

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

person zaius    schedule 17.08.2009
comment
проблема с to_i в том, что вы никогда не узнаете, 0 это или не число. - person moogs; 17.08.2009

Не знаю, быстро ли это, но мне нравится:

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

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

person moogs    schedule 17.08.2009
comment
Это действительно работает? Откуда object? На моем ruby ​​1.9.2-p180 он всегда возвращает false, потому что object не определен. - person mark; 07.04.2011
comment
Я думаю, что object в этом случае должно быть self. - person aridlehoover; 08.09.2018

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

Логика Залуса верна. Требуется только один раз проверить недопустимую строку.

person Lonecat    schedule 18.08.2009

Уведомление

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

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

работает для положительных и отрицательных целых чисел, но не для восьмеричных / шестнадцатеричных представлений, чисел с плавающей запятой и т.д.

person DavidJ    schedule 31.07.2012