Мне нужна функция,, is_an_integerгде
"12".is_an_integer?возвращает истину."blah".is_an_integer?возвращает false.
Как я могу сделать это в Ruby? Я бы написал регулярное выражение, но предполагаю, что для этого есть помощник, о котором я не знаю.
Мне нужна функция,, is_an_integerгде
"12".is_an_integer? возвращает истину."blah".is_an_integer? возвращает false.Как я могу сделать это в Ruby? Я бы написал регулярное выражение, но предполагаю, что для этого есть помощник, о котором я не знаю.
Ответы:
Вы можете использовать регулярные выражения. Вот функция с предложениями @janm.
class String
def is_i?
!!(self =~ /\A[-+]?[0-9]+\z/)
end
end
Отредактированная версия согласно комментарию @wich:
class String
def is_i?
/\A[-+]?\d+\z/ === self
end
end
Если вам нужно проверить только положительные числа
if !/\A\d+\z/.match(string_to_check)
#Is not a positive number
else
#Is all good ..continue
end
/regexp/ === selfвместо !!(self =~ /regexp/)конструкции. Вы можете использовать класс символов «\ d» вместо[0-9]
Что ж, вот простой способ:
class String
def is_integer?
self.to_i.to_s == self
end
end
>> "12".is_integer?
=> true
>> "blah".is_integer?
=> false
Я не согласен с решениями, которые вызывают исключение для преобразования строки - исключения не являются потоком управления, и вы также можете сделать это правильно. Тем не менее, мое вышеприведенное решение не касается целых чисел, отличных от десятичной. Итак, вот способ обойтись, не прибегая к исключениям:
class String
def integer?
[ # In descending order of likeliness:
/^[-+]?[1-9]([0-9]*)?$/, # decimal
/^0[0-7]+$/, # octal
/^0x[0-9A-Fa-f]+$/, # hexadecimal
/^0b[01]+$/ # binary
].each do |match_pattern|
return true if self =~ match_pattern
end
return false
end
end
self.to_i.to_s == selfна Integer self rescue false?
Вы можете использовать Integer(str)и посмотреть, поднимается ли он:
def is_num?(str)
!!Integer(str)
rescue ArgumentError, TypeError
false
end
Следует отметить, что, хотя это действительно возвращает true для "01", это не для "09", просто потому, 09что не будет действительным целочисленным литералом. Если это не то поведение, которое вам нужно, вы можете добавить его 10в качестве второго аргумента Integer, чтобы число всегда интерпретировалось как основание 10.
#to_iслишком ломаются из-за своей вседозволенности.
Integer()является каноническим, потому что Integer ()вы точно знаете, что все, что Ruby считает целочисленным литералом, будет принято, а все остальное будет отклонено. Дублирование того, что уже дает вам язык, - возможно, худший запах кода, чем использование исключений для контроля.
Вы можете сделать один лайнер:
str = ...
int = Integer(str) rescue nil
if int
int.times {|i| p i}
end
или даже
int = Integer(str) rescue false
В зависимости от того, что вы пытаетесь сделать, вы также можете напрямую использовать начальный конечный блок с предложением rescue:
begin
str = ...
i = Integer(str)
i.times do |j|
puts j
end
rescue ArgumentError
puts "Not an int, doing something else"
end
"12".match(/^(\d)+$/) # true
"1.2".match(/^(\d)+$/) # false
"dfs2".match(/^(\d)+$/) # false
"13422".match(/^(\d)+$/) # true
trueа falseтолько MatchDataэкземпляры иnil
!!или используйте, present?если вам нужно логическое значение !!( "12".match /^(\d)+$/ )или "12".match(/^(\d)+$/).present?(последнее требует Rails / activesupport)
Ruby 2.6.0 разрешает приведение к целому числу без возникновения исключения и вернется, nilесли приведение завершится неудачно. И поскольку в nilосновном ведет себя как falseв Ruby, вы можете легко проверить целое число следующим образом:
if Integer(my_var, exception: false)
# do something if my_var can be cast to an integer
end
class String
def integer?
Integer(self)
return true
rescue ArgumentError
return false
end
end
is_. Я нахожу это глупым в методах вопросительного знака, мне нравится "04".integer?намного больше, чем "foo".is_integer?."01"и тому подобное.integer?("a string")FTL.
String#integer?это своего рода общий патч, который каждый Ruby-программист и его двоюродный брат любят добавлять в язык, что приводит к кодовым базам с тремя различными слегка несовместимыми реализациями и неожиданным сбоям. Я усвоил это на собственном горьком опыте на больших проектах Ruby.
Самый лучший и простой способ - использовать Float
val = Float "234" rescue nil
Float "234" rescue nil #=> 234.0
Float "abc" rescue nil #=> nil
Float "234abc" rescue nil #=> nil
Float nil rescue nil #=> nil
Float "" rescue nil #=> nil
Integerтакже хорошо , но он вернется 0кInteger nil
Я предпочитаю:
конфиг / Инициализаторы / string.rb
class String
def number?
Integer(self).is_a?(Integer)
rescue ArgumentError, TypeError
false
end
end
а потом:
[218] pry(main)> "123123123".number?
=> true
[220] pry(main)> "123 123 123".gsub(/ /, '').number?
=> true
[222] pry(main)> "123 123 123".number?
=> false
или проверьте номер телефона:
"+34 123 456 789 2".gsub(/ /, '').number?
Более простой способ мог бы быть
/(\D+)/.match('1221').nil? #=> true
/(\D+)/.match('1a221').nil? #=> false
/(\D+)/.match('01221').nil? #=> true
def isint(str)
return !!(str =~ /^[-+]?[1-9]([0-9]*)?$/)
end
Лично мне нравится подход с исключениями, хотя я бы сделал его немного короче:
class String
def integer?(str)
!!Integer(str) rescue false
end
end
Однако, как уже говорили другие, это не работает с восьмеричными строками.
Ruby 2.4 имеет Regexp#match?: (с ?)
def integer?(str)
/\A[+-]?\d+\z/.match? str
end
Для более старых версий Ruby существует Regexp#===. И хотя прямого использования оператора равенства case следует избегать, здесь он выглядит очень чисто:
def integer?(str)
/\A[+-]?\d+\z/ === str
end
integer? "123" # true
integer? "-123" # true
integer? "+123" # true
integer? "a123" # false
integer? "123b" # false
integer? "1\n2" # false
Это может не подходить для всех случаев, просто используя:
"12".to_i => 12
"blah".to_i => 0
может также подойти для некоторых.
Если это число, а не 0, он вернет число. Если он возвращает 0, это либо строка, либо 0.
"12blah".to_i => 12. Это может вызвать некоторые проблемы в необычных сценариях.
Вот мое решение:
# /initializers/string.rb
class String
IntegerRegex = /^(\d)+$/
def integer?
!!self.match(IntegerRegex)
end
end
# any_model_or_controller.rb
'12345'.integer? # true
'asd34'.integer? # false
А вот как это работает:
/^(\d)+$/является регулярным выражением выражения для поиска цифр в любой строке. Вы можете проверить свои регулярные выражения и результаты на http://rubular.com/ .IntegerRegexчтобы избежать ненужного выделения памяти каждый раз, когда мы используем его в методе.integer?- это вопросительный метод, который должен возвращать trueили false.match - это метод для строки, который сопоставляет вхождения в соответствии с заданным выражением регулярного выражения в аргументе и возвращает сопоставленные значения или nil .!!преобразует результат matchметода в эквивалентное логическое значение.Stringклассе - это исправление обезьяны, которое ничего не меняет в существующих функциях String, а просто добавляет другой метод, названный integer?для любого объекта String.Расширяя ответ @rado выше, можно также использовать тернарный оператор для принудительного возврата истинных или ложных логических значений без использования двойного удара. Конечно, версия с двойным логическим отрицанием более лаконична, но, вероятно, труднее читать новичкам (например, мне).
class String
def is_i?
self =~ /\A[-+]?[0-9]+\z/ ? true : false
end
end
Для более общих случаев (включая числа с десятичной точкой) вы можете попробовать следующий метод:
def number?(obj)
obj = obj.to_s unless obj.is_a? String
/\A[+-]?\d+(\.[\d]+)?\z/.match(obj)
end
Вы можете протестировать этот метод в сеансе irb:
(irb)
>> number?(7)
=> #<MatchData "7" 1:nil>
>> !!number?(7)
=> true
>> number?(-Math::PI)
=> #<MatchData "-3.141592653589793" 1:".141592653589793">
>> !!number?(-Math::PI)
=> true
>> number?('hello world')
=> nil
>> !!number?('hello world')
=> false
Подробное объяснение задействованного здесь регулярного выражения можно найти в этой статье блога :)
obj.is_a? Stringпотому что String # to_s вернет сам себя, что, я думаю, не требует слишком большой обработки по сравнению с .is_a?вызовом. Таким образом, вы будете делать только один звонок в этой линии вместо одного или двух. Кроме того, вы можете включить его непосредственно !!в number?метод, поскольку по соглашению имя метода, которое заканчивается на ?, должно возвращать логическое значение. С уважением!
Я не уверен, было ли это когда-то, когда задают этот вопрос, но для всех, кто наткнется на этот пост, самый простой способ:
var = "12"
var.is_a?(Integer) # returns false
var.is_a?(String) # returns true
var = 12
var.is_a?(Integer) # returns true
var.is_a?(String) # returns false
.is_a? будет работать с любым объектом.
"12".is_an_integer? == true "not12".is_an_integer? == false 12.is_an_integer? == true