How to test if a string is basically an integer in quotes using Ruby
RubyRuby Problem Overview
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.
Ruby Solutions
Solution 1 - Ruby
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
Solution 2 - Ruby
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
Solution 3 - Ruby
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.
Solution 4 - Ruby
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
Solution 5 - Ruby
"12".match(/^(\d)+$/) # true
"1.2".match(/^(\d)+$/) # false
"dfs2".match(/^(\d)+$/) # false
"13422".match(/^(\d)+$/) # true
Solution 6 - Ruby
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
Solution 7 - Ruby
class String
def integer?
Integer(self)
return true
rescue ArgumentError
return false
end
end
- It isn't prefixed with
is_
. I find that silly on questionmark methods, I like"04".integer?
a lot better than"foo".is_integer?
. - It uses the sensible solution by sepp2k, which passes for
"01"
and such. - Object oriented, yay.
Solution 8 - Ruby
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
Solution 9 - Ruby
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?
Solution 10 - Ruby
A much simpler way could be
/(\D+)/.match('1221').nil? #=> true
/(\D+)/.match('1a221').nil? #=> false
/(\D+)/.match('01221').nil? #=> true
Solution 11 - Ruby
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.
Solution 12 - Ruby
def isint(str)
return !!(str =~ /^[-+]?[1-9]([0-9]*)?$/)
end
Solution 13 - Ruby
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.
Solution 14 - Ruby
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/.- We save it in a constant
IntegerRegex
to avoid unnecessary memory allocation everytime we use it in the method. integer?
is an interrogative method which should returntrue
orfalse
.match
is a method on string which matches the occurrences as per the given regex expression in argument and return the matched values ornil
.!!
converts the result ofmatch
method into equivalent boolean.- And declaring the method in existing
String
class is monkey patching, which doesn't change anything in existing String functionalities, but just adds another method namedinteger?
on any String object.
Solution 15 - Ruby
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
Solution 16 - Ruby
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
Solution 17 - Ruby
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 :)
Solution 18 - Ruby
One liner in string.rb
def is_integer?; true if Integer(self) rescue false end
Solution 19 - Ruby
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.