Фон
Правильная реализация проверки ввода - один из самых фундаментальных аспектов любого веб-приложения. Хотя мы можем полагаться на некоторые из существующих методов для достижения многих типов проверки ввода, некоторые методы могут быть не такими гибкими, как нам хотелось бы.
Например, метод Object#is_a?
позволяет нам проверить, имеет ли вызывающий объект определенный тип:
>> 12.is_a? Integer => true >> 'foo'.is_a? String => true >> [1, 2, 3].is_a? Array => false
Этот метод работает хорошо, пока мы не введем объекты, которые выглядят как число, массив и т. Д.:
>> '12'.is_a? Integer => false >> '[1, 2, 3]'.is_a? Array => false
Причина, по которой они возвращают false
, конечно же, заключается в том, что эти вызывающие объекты на самом деле являются строками, а не целым числом или массивом.
Здесь мы хотим избежать обработки этих входных данных как строк, поскольку мы заинтересованы в проверке того, что находится «внутри» строк.
Разве не было бы неплохо, если бы у нас был метод, который мог бы иметь любые типы аргументов в качестве входных данных, проверять «внутреннее значение» входных данных и проверять, относится ли он к определенному типу, который мы указываем?
Реализация
Описанная ниже реализация ориентирована на проверку числа в Ruby. Точнее, он проверит, принадлежит ли «содержимое» данного ввода произвольного типа к одному из следующих типов (классов): Integer, Float.
def number?(obj) obj = obj.to_s unless obj.is_a? String /\A[+-]?\d+(\.[\d]+)?\z/.match(obj) end
Начнем с анализа регулярного выражения:
/\A[+-]?\d+(\.\d+)?\z/
Вот список элементов, содержащихся в регулярном выражении.
/ start of the regex \A start of the string to be matched [+-]? zero or one of '+' or'-' \d+ one or more of digit (\.\d+)? zero or one of 'one dot and 'one or more of digit'' \z end of the string to be matched / end of the regex
(Для получения более подробной информации о синтаксисе регулярных выражений в целом вы можете проверить этот краткий справочник по регулярным выражениям.)
Давайте перейдем к irb, чтобы убедиться, что регулярное выражение действительно работает:
(irb) REGEX = /\A[+-]?\d+(\.[\d]+)?\z/ REGEX.match '13' => #<MatchData "13" 1:nil> !!REGEX.match '13' => true REGEX.match '3.14' => #<MatchData "3.14" 1:".14"> !!REGEX.match '3.14' => true REGEX.match 'not a number' => nil !!REGEX.match 'not a number' => false
Метод Regexp # match в приведенном выше примере возвращает объект MatchData, если проверяемая строка представляет собой число. В противном случае он вернет nil
. Обозначение с двойным восклицательным знаком (!!
) используется здесь для преобразования возвращаемого значения в соответствующее ему логическое значение.
Обратите внимание, что метод сопоставления выдаст ошибку при передаче в качестве аргумента нестрокового объекта:
(irb) REGEX = /\A[+-]?\d+(\.[\d]+)?\z/ REGEX.match 13 => TypeError: no implicit conversion of Integer into String ... REGEX.match 3.14 => TypeError: no implicit conversion of Float into String ...
Чтобы этого избежать, мы добавим следующий код (*):
obj.to_s unless obj.is_a? String (*)
(«Obj» - это объект, который мы хотим протестировать на соответствие регулярному выражению) Эта строка кода преобразует объект в объект String, если объект не относится к типу String, и гарантирует, что мы можем использовать этот объект String для проверки на соответствие регулярному выражению.
Это завершает объяснение того, как вышеуказанный метод:
def number?(obj) obj = obj.to_s unless obj.is_a? String /\A[+-]?\d+(\.[\d]+)?\z/.match obj end
работает.
Вот пример того, как мы можем использовать этот метод (в этом примере код (*) является необязательным, поскольку «число» всегда будет иметь тип String после присвоения значения через gets.chomp
, метод, который возвращает строку:
puts "Enter a number:" number = nil loop do number = gets.chomp break if number?(number) puts "That is not a number." end puts "#{number} is indeed a number."
Запуск этого кода выводит на печать следующее:
Enter a number: foo That is not a number. bar That is not a number. ‘12.34’ That is not a number. 12.3.4 That is not a number. 12.34 12.34 is indeed a number.
использованная литература
Вам также могут быть полезны следующие ресурсы по этой теме:
«Http://stackoverflow.com/questions/1235863/test-if-a-string-is-basically-an-integer-in-quotes-using-rub lesy
Http://rubular.com/ (интерактивный редактор регулярных выражений Ruby)
Если есть области, которые, по вашему мнению, можно улучшить, дайте мне знать в разделе комментариев ниже. Мы будем благодарны за любые отзывы!