Как заставить пользователя только набирать числа [дублировать]

Если мы рассмотрим общие сценарии, в которых может быть выбрано это исключение, доступ к свойствам с объектом вверху.

Пример:

string postalcode=Customer.Address.PostalCode; 
//if customer or address is null , this will through exeption

здесь, если адрес имеет значение null, то вы получите NullReferenceException.

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

string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception
112
задан Tony 5 August 2009 в 22:28
поделиться

19 ответов

Вы можете использовать регулярные выражения. Вот функция с предложениями @ 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  
120
ответ дан sscirrus 25 August 2018 в 18:38
поделиться
  • 1
    Неплохо. В Ruby вы обычно опускаете & quot; return & quot; если возвращаемое значение генерируется в последнем выражении в функции. Это также вернет целочисленное значение нуля, вы, вероятно, хотите иметь логическое значение, поэтому что-то вроде !! (str = ~ / ^ [- +]? [0-9] + $ /). Затем вы можете добавить его в String и оставить аргумент, используя & quot; self & quot; вместо "str", а затем вы можете изменить имя на "is_i? & quot; ... – janm 5 August 2009 в 23:16
  • 2
    Благодаря! У меня нет абсолютно никакой информации о рубиновых конвенциях и практиках. Я просто сделал быстрый google на рубине и регулярных выражениях, чтобы увидеть синтаксис, изменил регулярное выражение, чтобы применить к проблеме, и протестировал ее. Это довольно аккуратно. Возможно, мне придется больше смотреть на него, когда у меня будет больше свободного времени. – Rado 5 August 2009 в 23:21
  • 3
    У вас есть правильная идея, но она не соответствует бинарным или шестнадцатеричным литералам (см. Мое отредактированное решение ниже). – Sarah Mei 6 August 2009 в 04:56
  • 4
    Сара, это не ошибка, это особенность! – janm 6 August 2009 в 08:51
  • 5
    Два комментария. Вы можете использовать /regexp/ === self вместо конструкции !!(self =~ /regexp/). Вы можете использовать класс символов '\ d' вместо [0-9] – wich 24 September 2012 в 02:24

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

class String
  def is_i?
     self =~ /\A[-+]?[0-9]+\z/ ? true : false
  end
end
0
ответ дан adeluccar 25 August 2018 в 18:38
поделиться
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. Объектно-ориентированный, yay.
8
ответ дан August Lilleaas 25 August 2018 в 18:38
поделиться
  • 1
    +1 для его именования #integer ?, -1 для загромождения String с ним: -P – Avdi 5 August 2009 в 22:45
  • 2
    Куда еще это пойдет? integer?("a string") ftl. – August Lilleaas 5 August 2009 в 22:47
  • 3
    String#integer? - это общий патч, который каждый рубиновый кодер и их кузен любят добавлять к языку, приводя к кодовым базам с тремя различными тонко несовместимыми реализациями и неожиданным поломкой. Я усвоил это на крупных проектах Ruby. – Avdi 5 August 2009 в 22:51
  • 4
    Те же комментарии, что и выше: исключения не должны использоваться для потока управления. – Sarah Mei 5 August 2009 в 23:08
  • 5
    Даунсайд: это решение тратит одно конвертирование. – Robert Klemme 31 January 2014 в 19:02
  def isint(str)
    return !!(str =~ /^[-+]?[1-9]([0-9]*)?$/)
  end
3
ответ дан Brian Webster 25 August 2018 в 18:38
поделиться
3
ответ дан eightbitraptor 25 August 2018 в 18:38
поделиться

Более простым способом может быть

/(\D+)/.match('1221').nil? #=> true
/(\D+)/.match('1a221').nil? #=> false
/(\D+)/.match('01221').nil? #=> true
3
ответ дан gouravtiwari21 25 August 2018 в 18:38
поделиться
"12".match(/^(\d)+$/)      # true
"1.2".match(/^(\d)+$/)     # false
"dfs2".match(/^(\d)+$/)    # false
"13422".match(/^(\d)+$/)   # true
18
ответ дан Maciej Krasowski 25 August 2018 в 18:38
поделиться
  • 1
    Он не возвращает экземпляры true и false, но MatchData и nil – Stefan 17 September 2013 в 14:19
  • 2
    Это не то, что оно возвращает, но если оно совпадает – Maciej Krasowski 8 August 2014 в 10:40
  • 3
    Оберните его с помощью !! или используйте present?, если вам нужны логические !!( "12".match /^(\d)+$/ ) или "12".match(/^(\d)+$/).present? (последние требуют Rails / activesupport) – mahemoff 17 September 2015 в 15:33

Вы можете использовать Integer(str) и посмотреть, возникает ли он:

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

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

60
ответ дан Milos 25 August 2018 в 18:38
поделиться
  • 1
    Чувак ... провоцирует исключение только для преобразования числа? Исключения не являются потоком управления. – Sarah Mei 5 August 2009 в 23:05
  • 2
    Это не так, но, к сожалению, это канонический способ определения «целочисленности». строки в Ruby. Методы, использующие #to_i, слишком нарушены из-за его вседозволенности. – Avdi 5 August 2009 в 23:17
  • 3
    Для тех, кто задается вопросом, почему Integer («09») недействителен, поскольку «0» делает его восьмеричным, а 9 - недействительным восьмеричным числом. osdir.com/ml/lang.ruby.general/2002-08/msg00247.html – Andrew Grimm 6 August 2009 в 00:25
  • 4
    Сара: вы можете использовать Regex, но для обработки всех случаев, которые Ruby делает при синтаксическом анализе целых чисел (отрицательные числа, шестнадцатеричные, восьмеричные, подчеркивания, например, 1_000_000), это будет очень большое Regex и легко ошибиться. Integer() является каноническим, потому что с Integer () вы точно знаете, что все, что Ruby считает целочисленным литералом, будет принято, а все остальное будет отклонено. Дублирование того, что уже дал вам язык, - это, пожалуй, худший запах кода, чем использование исключений для контроля. – Avdi 6 August 2009 в 15:32
  • 5
    @Rado Так изобретает колесо. – sepp2k 20 May 2014 в 21:13

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

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? будет работать с любым объектом!

-2
ответ дан Newbie 25 August 2018 в 18:38
поделиться
  • 1
    Это не то, что задает первоначальный вопрос. OP хочет знать, является ли строка целым числом. например "12".is_an_integer? == true "not12".is_an_integer? == false 12.is_an_integer? == true – Marklar 25 April 2016 в 11:40

Один вкладыш в string.rb

def is_integer?; true if Integer(self) rescue false end
-1
ответ дан Richard Erickson 25 August 2018 в 18:38
поделиться

Вы можете сделать один лайнер:

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
19
ответ дан Robert Klemme 25 August 2018 в 18:38
поделиться
  • 1
    Что касается темы «исключение как поток управления»: поскольку мы не знаем, как использовать метод, мы не можем действительно судить о том, подходят ли исключения или нет. Если строка вводится и требуется целое число, то предоставление не целого числа гарантирует исключение. Хотя тогда, возможно, обработка не в том же методе, и мы, вероятно, просто сделаем Integer (str) .times {| i | ставит i} или что угодно. – Robert Klemme 6 August 2009 в 08:07

Решение:

# /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)+$/ - выражение regex для нахождения цифр в любой строке. Вы можете проверить выражения и результаты регулярных выражений на http://rubular.com/ .
  • Мы сохраняем его в константе IntegerRegex, чтобы избежать ненужного выделения памяти каждый раз, когда мы ее используем в методе.
  • integer? - это вопросительный метод, который должен возвращать true или false.
  • match - метод в строке, который соответствует вхождениям в соответствии с данное выражение регулярного выражения в аргументе и возвращает согласованные значения или nil.
  • !! преобразует результат метода match в эквивалентный булев.
  • И объявив метод в существующий класс String - это исправление обезьяны, которое ничего не меняет в существующих функциях String, но добавляет еще один метод с именем integer? для любого объекта String.
2
ответ дан Sachin 25 August 2018 в 18:38
поделиться
  • 1
    Не могли бы вы добавить небольшое объяснение этому, пожалуйста? – stef 24 May 2017 в 08:08
  • 2
    @stef - Я сделал то же самое. Пожалуйста, дайте мне знать, если у вас есть какие-либо вопросы. – Sachin 25 May 2017 в 09:57

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

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

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

EDIT: Я не согласен с решениями, которые вызывают исключение для преобразования строки. Исключения - это не поток управления, и вы также можете сделайте это правильно. Тем не менее, мое решение выше не касается целых чисел, отличных от base-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
139
ответ дан Sarah Mei 25 August 2018 в 18:38
поделиться
  • 1
    "01" .to_i.to_s! = "01" – sepp2k 5 August 2009 в 22:37
  • 2
    Не могли бы вы заменить self.to_i.to_s == self на Integer self rescue false? – Meredith L. Patterson 5 August 2009 в 22:38
  • 3
    Вы могли бы, но это было бы плохой формой. Вы не используете исключения в качестве потока управления, и ни один код не должен содержать «rescue false». (или «спасение истинно»). Некоторые простые gsub'ing заставили бы мое решение работать для случаев кросс, не указанных OP. – Sarah Mei 5 August 2009 в 23:06
  • 4
    Я знаю, что многие используют его, и это, безусловно, эстетично. Для меня, хотя это показатель того, что код нуждается в реструктуризации. Если вы ожидаете исключения ... это не исключение. – Sarah Mei 6 August 2009 в 04:59
  • 5
    Я согласен с тем, что исключения не должны использоваться в качестве потока управления. Я не думаю, что требование состоит в том, чтобы распознанные числа, ориентированные на разработчиков. В ситуациях, отличных от программистов, которые можно рассматривать как ошибку, особенно учитывая ту возможную путаницу вокруг ведущих нулей и восьмеричных. Также не согласуется с to_i. Ваш код не обрабатывает & quot; -0123 & quot; дело. Как только вы справитесь с этим случаем, вам не нужно отдельное регулярное выражение для восьмеричного. Вы можете просто продолжить, используя «any?». Единственным утверждением в вашей функции может быть & quot; [/ re1 /, / re2 /, / re3 /] .any? {| re | self = ~ re} & quot ;, без предложений if или return. – janm 6 August 2009 в 08:49

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

4
ответ дан shiva 25 August 2018 в 18:38
поделиться
  • 1
    @downvoter вы можете объяснить? – shiva 19 November 2014 в 04:44
  • 2
    Я рад, что заметил ваш ответ. В противном случае я бы пошел с "Integer" когда мне понадобился «Float». – Jeff Zivkovic 30 May 2018 в 03:21
  • 3
    Это простой, но лучший ответ! В большинстве случаев нам не нужен модный патч для класса String. Это лучше для меня! – Anh Nguyen 28 June 2018 в 06:50

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

config / initializers / 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?
5
ответ дан skozz 25 August 2018 в 18:38
поделиться

Хотя следует избегать явного использования оператора равенства случая, 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
1
ответ дан Stefan 25 August 2018 в 18:38
поделиться

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

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

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

1
ответ дан Taiga 25 August 2018 в 18:38
поделиться
  • 1
    Нет необходимости вызывать obj.is_a? String, потому что String # to_s вернется, что, по моему мнению, не требует слишком большой обработки по сравнению с вызовом .is_a?. Таким образом, вы будете делать только один вызов в этой строке вместо одного или двух. Кроме того, вы можете включить непосредственно !! внутри метода number?, потому что по соглашению имя метода, которое заканчивается на ?, должно возвращать логическое значение. С уважением! – Giovanni Benussi 5 October 2017 в 15:32

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

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

.

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

2
ответ дан three 25 August 2018 в 18:38
поделиться
  • 1
    Работает, но это не рекомендуется, поскольку "12blah".to_i => 12. Это может вызвать некоторые проблемы в странных сценариях. – rfsbraz 17 June 2015 в 11:24

вы можете использовать is_a? метод. например. 1.is_a? Integer вернет true

-3
ответ дан Vedprakash Singh 25 August 2018 в 18:38
поделиться
  • 1
    Прочитайте вопрос, который OP хотел проверить, что для строк, а "1".is_a?(Integer) возвращает false – Cyril Duchon-Doris 25 February 2017 в 21:29
Другие вопросы по тегам:

Похожие вопросы: