Мне нужна функция,, 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