I need a function, is_an_integer
, where
"12".is_an_integer?
returns true."blah".is_an_integer?
returns false.
How can I do this in Ruby? I would write a regex but I'm assuming there is a helper for this that I am not aware of.
I need a function, is_an_integer
, where
"12".is_an_integer?
returns true."blah".is_an_integer?
returns false.How can I do this in Ruby? I would write a regex but I'm assuming there is a helper for this that I am not aware of.
You can use regular expressions. Here is the function with @janm's suggestions.
class String
def is_i?
!!(self =~ /\A[-+]?[0-9]+\z/)
end
end
An edited version according to comment from @wich:
class String
def is_i?
/\A[-+]?\d+\z/ === self
end
end
In case you only need to check positive numbers
if !/\A\d+\z/.match(string_to_check)
#Is not a positive number
else
#Is all good ..continue
end
/regexp/ === self
instead of the !!(self =~ /regexp/)
construct. You can use character class '\d' instead of [0-9]
–
Niggerhead Well, here's the easy way:
class String
def is_integer?
self.to_i.to_s == self
end
end
>> "12".is_integer?
=> true
>> "blah".is_integer?
=> false
I don't agree with the solutions that provoke an exception to convert the string - exceptions are not control flow, and you might as well do it the right way. That said, my solution above doesn't deal with non-base-10 integers. So here's the way to do with without resorting to exceptions:
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
with Integer self rescue false
? –
Quadrennium '$1,000'.to_i.to_s == '$1,000'
fails. –
Mirza " 1"
–
Linnette '-0'.is_integer? == false
–
Angelita value.is_a? Integer
. –
Favorite self.to_i.to_s == self.sub(/^0+/,"")
–
Shamefaced |
, and run it once. –
Coolth Integer
for answering the question of whether a string contains a valid number, it's localized, robust, and easy to reason about code. The regex solution is harder to reason about and has greater potential for edge cases that need to be handled, in some cases complicating it further. The accepted answer had one such issue for several years, and this answer still has that same issue at the time of this writing. It matches strings such as "abc\n123\ndef". –
Phosphene '1.0'.to_i.to_s != '1.0'
–
Sailesh '+2'.is_integer?
is false
–
Sheppard You can use regular expressions. Here is the function with @janm's suggestions.
class String
def is_i?
!!(self =~ /\A[-+]?[0-9]+\z/)
end
end
An edited version according to comment from @wich:
class String
def is_i?
/\A[-+]?\d+\z/ === self
end
end
In case you only need to check positive numbers
if !/\A\d+\z/.match(string_to_check)
#Is not a positive number
else
#Is all good ..continue
end
/regexp/ === self
instead of the !!(self =~ /regexp/)
construct. You can use character class '\d' instead of [0-9]
–
Niggerhead You can use Integer(str)
and see if it raises:
def is_num?(str)
!!Integer(str)
rescue ArgumentError, TypeError
false
end
It should be pointed out that while this does return true for "01"
, it does not for "09"
, simply because 09
would not be a valid integer literal. If that's not the behaviour you want, you can add 10
as a second argument to Integer
, so the number is always interpreted as base 10.
#to_i
are just too broken because of it's permissiveness. –
Monroemonroy Integer()
is canonical because with Integer ()
you know for sure that anything that Ruby considers an integer literal will be accepted, and everything else will be rejected. Duplicating what the language already gives you is arguably a worse code smell than using exceptions for control. –
Monroemonroy Integer(str)
will convert strings like 0x26
, so a better method to use might be Integer(str, 10)
. The 10 will only accept base 10 numbers. –
Superheterodyne raise ArgumentError
and later rescued from that exception. –
Reclaim str
happens to be a Float value, like 1.23
, this will return true because Integer(1.23) will convert the number to integer. –
Marlomarlon !!Integer(1.25) rescue false => true
(note the lack of quotes) –
Marlomarlon Ruby 2.6.0 enables casting to an integer without raising an exception, and will return nil
if the cast fails. And since nil
mostly behaves like false
in Ruby, you can easily check for an integer like so:
if Integer(my_var, exception: false)
# do something if my_var can be cast to an integer
end
"2hey".to_i == 2
returns true
, but Integer("2hey", exception: false)
returns nil
–
Interface You can do a one liner:
str = ...
int = Integer(str) rescue nil
if int
int.times {|i| p i}
end
or even
int = Integer(str) rescue false
Depending on what you are trying to do you can also directly use a begin end block with rescue clause:
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
and false
but MatchData
instances and nil
–
Charmainecharmane !!
or use present?
if you need a boolean !!( "12".match /^(\d)+$/ )
or "12".match(/^(\d)+$/).present?
(the latter requiring Rails/activesupport) –
Hag class String
def integer?
Integer(self)
return true
rescue ArgumentError
return false
end
end
is_
. I find that silly on questionmark methods, I like "04".integer?
a lot better than "foo".is_integer?
."01"
and such.integer?("a string")
ftl. –
Perigee String#integer?
is the kind of common patch that every Ruby coder and their cousin likes to add to the language, leading to codebases with three different subtly incompatible implementations and unexpected breakage. I learned this the hard way on large Ruby projects. –
Monroemonroy The Best and Simple way is using 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
is also good but it will return 0
for Integer nil
I prefer:
config/initializers/string.rb
class String
def number?
Integer(self).is_a?(Integer)
rescue ArgumentError, TypeError
false
end
end
and then:
[218] pry(main)> "123123123".number?
=> true
[220] pry(main)> "123 123 123".gsub(/ /, '').number?
=> true
[222] pry(main)> "123 123 123".number?
=> false
or check phone number:
"+34 123 456 789 2".gsub(/ /, '').number?
Personally I like the exception approach although I would make it a little more terse:
class String
def integer?(str)
!!Integer(str) rescue false
end
end
However, as others have already stated, this doesn't work with Octal strings.
A much simpler way could be
/(\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
Ruby 2.4 has Regexp#match?
: (with a ?
)
def integer?(str)
/\A[+-]?\d+\z/.match? str
end
For older Ruby versions, there's Regexp#===
. And although direct use of the case equality operator should generally be avoided, it looks very clean here:
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
This might not be suitable for all cases simplely using:
"12".to_i => 12
"blah".to_i => 0
might also do for some.
If it's a number and not 0 it will return a number. If it returns 0 it's either a string or 0.
"12blah".to_i => 12
. This might cause some trouble in weird scenarios. –
Northerly Here's my solution:
# /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
And here's how it works:
/^(\d)+$/
is regex expression for finding digits in any string. You can test your regex expressions and results at http://rubular.com/.IntegerRegex
to avoid unnecessary memory allocation everytime we use it in the method.integer?
is an interrogative method which should return true
or false
.match
is a method on string which matches the occurrences as per the given regex expression in argument and return the matched values or nil
.!!
converts the result of match
method into equivalent boolean.String
class is monkey patching, which doesn't change anything in existing String functionalities, but just adds another method named integer?
on any String object. Expanding on @rado's answer above one could also use a ternary statement to force the return of true or false booleans without the use of double bangs. Granted, the double logical negation version is more terse, but probably harder to read for newcomers (like me).
class String
def is_i?
self =~ /\A[-+]?[0-9]+\z/ ? true : false
end
end
For more generalised cases (including numbers with decimal point), you can try the following method:
def number?(obj)
obj = obj.to_s unless obj.is_a? String
/\A[+-]?\d+(\.[\d]+)?\z/.match(obj)
end
You can test this method in an irb session:
(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
For a detailed explanation of the regex involved here, check out this blog article :)
obj.is_a? String
because String#to_s will return itself, which I guess doesn't require too much processing compared with the .is_a?
call. This way, you'll be making only one call in this line instead of one or two. Also, you could include directly !!
inside the number?
method, because by convention, a method name that ends with ?
is supposed to return a boolean value. Regards! –
Michelinamicheline One liner in string.rb
def is_integer?; true if Integer(self) rescue false end
I'm not sure if this was around when this question is asked but for anyone that stumbles across this post, the simplest way is:
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?
will work with any object.
"12".is_an_integer? == true
"not12".is_an_integer? == false
12.is_an_integer? == true
–
Rodrigorodrigue © 2022 - 2024 — McMap. All rights reserved.