Проверить, является ли строка в целом целым числом в кавычках, используя Ruby?

Мне нужна функция is_an_integer, где

"12".is_an_integer? returns true
"blah".is_an_integer? returns false

как я могу сделать это в рубине? я бы написал регулярное выражение, но я предполагаю, что есть помощник для этого, о котором я не знаю

20 ответов

Решение

Вы можете использовать регулярные выражения. Вот функция с предложениями @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  

Ну вот простой способ:

class String
  def is_integer?
    self.to_i.to_s == self
  end
end

>> "12".is_integer?
=> true
>> "blah".is_integer?
=> false

РЕДАКТИРОВАТЬ: Я не согласен с решениями, которые вызывают исключение для преобразования строки - исключения не поток управления, и вы могли бы также сделать это правильно. Тем не менее, мое решение выше не имеет дело с целыми числами не-10. Итак, вот как это сделать, не прибегая к исключениям:

  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

Ты можешь использовать Integer(str) и посмотрим, поднимется ли она:

def is_num?(str)
  !!Integer(str, 10)
rescue ArgumentError, TypeError
  false
end

Приложение: Следует отметить, что хотя это действительно вернет "01"не для "09", просто потому что 09 не будет действительным целочисленным литералом.

Приложение к приложению: исправлено путем изменения Integer(str) в Integer(str, 10)согласно комментарию @jason-axelson.

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
"12".match(/^(\d)+$/)      # true
"1.2".match(/^(\d)+$/)     # false
"dfs2".match(/^(\d)+$/)    # false
"13422".match(/^(\d)+$/)   # true

Вы можете сделать один вкладыш:

str = ...
int = Integer(str) rescue nil

if int
  int.times {|i| p i}
end

или даже

int = Integer(str) rescue false

В зависимости от того, что вы пытаетесь сделать, вы также можете напрямую использовать начальный конечный блок с предложением восстановления:

begin
  str = ...
  i = Integer(str)

  i.times do |j|
    puts j
  end
rescue ArgumentError
  puts "Not an int, doing something else"
end

Лучший и простой способ использует 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

class String
  def integer?
    Integer(self)
    return true
  rescue ArgumentError
    return false
  end
end
  1. Это не префикс с is_, Я считаю, что глупо на вопросительных знаках, мне нравится "04".integer? намного лучше чем "foo".is_integer?,
  2. Он использует разумное решение от sepp2k, которое проходит для "01" и тому подобное.
  3. Объектно-ориентированный, ура.

Я предпочитаю:

конфиг / Инициализаторы /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?

Лично мне нравится подход исключения, хотя я сделал бы это немного более кратким.

class String
  def integer?(str)
    !!Integer(str) rescue false
  end
end

Однако, как уже говорили другие, это не работает с октальными строками...

Гораздо проще может быть

/(\D+)/.match('1221').nil? #=> true
/(\D+)/.match('1a221').nil? #=> false
/(\D+)/.match('01221').nil? #=> true

Может не подходить для всех случаев, но простой

"12".to_i   => 12
"blah".to_i => 0

может также сделать для некоторых.

Так что, если это число, а не 0, оно вернет число. Если он возвращает 0, это либо слово, либо 0.

Решение:

# /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.
  def isint(str)
    return !!(str =~ /^[-+]?[1-9]([0-9]*)?$/)
  end

Хотя явного использования оператора равенства регистра следует избегать, Regexp#=== выглядит очень чисто здесь:

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

Для более обобщенных случаев (включая числа с десятичной точкой) вы можете попробовать следующий метод:

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

Для подробного объяснения регулярного выражения здесь, проверьте эту статью в блоге:)

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

class String
  def is_i?
     self =~ /\A[-+]?[0-9]+\z/ ? true : false
  end
end

Один лайнер в string.rb

def is_integer?; true if Integer(self) rescue false end

Мне нравится следующее:

def is_integer?(str)
  str.to_i != 0 || str == '0' || str == '-0'
end

is_integer?('123')
=> true

is_integer?('sdf')
=> false

is_integer?('-123')
=> true

is_integer?('0')
=> true

is_integer?('-0')
=> true

Но осторожно:

is_integer?('123sdfsdf')
=> true

Я не уверен, было ли это когда задан этот вопрос, но... Для всех, кто наткнулся на этот пост, самый простой способ

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? метод. например, 1.is_a? Целое число вернет истину

Другие вопросы по тегам