Мені потрібна функція is_an_integer
, де
"12".is_an_integer?
повертає правду."blah".is_an_integer?
повертає помилкове.
Як я можу це зробити в Ruby? Я б написав регулярний вираз, але я припускаю, що для цього є помічник, про який я не знаю.
Мені потрібна функція is_an_integer
, де
"12".is_an_integer?
повертає правду."blah".is_an_integer?
повертає помилкове.Як я можу це зробити в 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
Я не згоден з рішеннями, які провокують виняток для перетворення рядка - винятки не є контролем потоку, і ви також можете зробити це правильно. Враховуючи це, моє рішення вище не стосується цілих чисел без бази-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
self.to_i.to_s == self
з Integer self rescue false
?
Ви можете використовувати Integer(str)
та бачити, чи підвищується він:
def is_num?(str)
!!Integer(str)
rescue ArgumentError, TypeError
false
end
Слід зазначити, що хоча це справді повертає істину для "01"
, це не робиться "09"
, просто тому, 09
що не було б дійсним цілим числовим буквалом. Якщо це не поведінка, яку ви хочете, ви можете додати 10
як другий аргумент Integer
, тому число завжди інтерпретується як базове 10.
#to_i
, просто надто порушені через вседозволеність.
Integer()
є канонічним, оскільки Integer ()
ви точно знаєте, що все, що Рубі вважає цілим літералом, буде прийнято, а все інше буде відхилено. Дублювання того, що мова вже дає вам, можливо, гірший запах коду, ніж використання виключень для контролю.
Ви можете зробити один вкладиш:
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
"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
Я віддаю перевагу:
config / ініціалізатори / 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
Однак, як уже зазначали інші, це не працює з Octal рядками.
Ruby 2.4 має Regexp#match?
: (з a ?
)
def integer?(str)
/\A[+-]?\d+\z/.match? str
end
Для старих версій Ruby є 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
Це може бути не підходить для всіх випадків, просто використовуючи:
"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
тому що рядок # to_s повернеться сам, що, напевно, не вимагає занадто багато обробки в порівнянні з .is_a?
викликом. Таким чином, ви будете здійснювати лише один дзвінок у цій лінії замість одного чи двох. Крім того, ви можете включити безпосередньо !!
всередину number?
методу, оскільки, за умовою, ім'я методу, яке закінчується ?
, повинно повернути булеве значення. З повагою!
Мені подобається наступне, прямо вперед:
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?
буде працювати з будь-яким об’єктом.
"12".is_an_integer? == true
"not12".is_an_integer? == false
12.is_an_integer? == true