Does Rails 3 or Ruby have a built-in way to check if a variable is an integer?
For example,
1.is_an_int #=> true
"dadadad#asdasd.net".is_an_int #=> false?
You can use the is_a? method
>> 1.is_a? Integer
=> true
>> "dadadad#asdasd.net".is_a? Integer
=> false
>> nil.is_a? Integer
=> false
If you want to know whether an object is an Integer or something which can meaningfully be converted to an Integer (NOT including things like "hello", which to_i will convert to 0):
result = Integer(obj) rescue false
Use a regular expression on a string:
def is_numeric?(obj)
obj.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/) == nil ? false : true
end
If you want to check if a variable is of certain type, you can simply use kind_of?:
1.kind_of? Integer #true
(1.5).kind_of? Float #true
is_numeric? "545" #true
is_numeric? "2aa" #false
If you're uncertain of the type of the variable (it could be a string of number characters), say it was a credit card number passed into the params, so it would originally be a string but you want to make sure it doesn't have any letter characters in it, I would use this method:
def is_number?(obj)
obj.to_s == obj.to_i.to_s
end
is_number? "123fh" # false
is_number? "12345" # true
#Benny points out an oversight of this method, keep this in mind:
is_number? "01" # false. oops!
There's var.is_a? Class (in your case: var.is_a? Integer); that might fit the bill. Or there's Integer(var), where it'll throw an exception if it can't parse it.
You can use triple equal.
if Integer === 21
puts "21 is Integer"
end
A more "duck typing" way is to use respond_to? this way "integer-like" or "string-like" classes can also be used
if(s.respond_to?(:match) && s.match(".com")){
puts "It's a .com"
else
puts "It's not"
end
In case you don't need to convert zero values, I find the methods to_i and to_f to be extremely useful since they will convert the string to either a zero value (if not convertible or zero) or the actual Integer or Float value.
"0014.56".to_i # => 14
"0014.56".to_f # => 14.56
"0.0".to_f # => 0.0
"not_an_int".to_f # 0
"not_a_float".to_f # 0.0
"0014.56".to_f ? "I'm a float" : "I'm not a float or the 0.0 float"
# => I'm a float
"not a float" ? "I'm a float" : "I'm not a float or the 0.0 float"
# => "I'm not a float or the 0.0 float"
EDIT2 : be careful, the 0 integer value is not falsey it's truthy (!!0 #=> true) (thanks #prettycoder)
EDIT
Ah just found out about the dark cases... seems to only happen if the number is in first position though
"12blah".to_i => 12
To capitalize on the answer of Alex D, using refinements:
module CoreExtensions
module Integerable
refine String do
def integer?
Integer(self)
rescue ArgumentError
false
else
true
end
end
end
end
Later, in you class:
require 'core_ext/string/integerable'
class MyClass
using CoreExtensions::Integerable
def method
'my_string'.integer?
end
end
I have had a similar issue before trying to determine if something is a string or any sort of number whatsoever. I have tried using a regular expression, but that is not reliable for my use case. Instead, you can check the variable's class to see if it is a descendant of the Numeric class.
if column.class < Numeric
number_to_currency(column)
else
column.html_safe
end
In this situation, you could also substitute for any of the Numeric descendants: BigDecimal, Date::Infinity, Integer, Fixnum, Float, Bignum, Rational, Complex
Basically, an integer n is a power of three, if there exists an integer x such that n == 3x.
So to verify that you can use this functions
def is_power_of_three(n)
return false unless n.positive?
n == 3**(Math.log10(n)/Math.log10(3)).to_f.round(2)
end
Probably you are looking for something like this:
Accept "2.0 or 2.0 as an INT but reject 2.1 and "2.1"
num = 2.0
if num.is_a? String num = Float(num) rescue false end
new_num = Integer(num) rescue false
puts num
puts new_num
puts num == new_num
Related
I am trying this :
print " Enter Value "
num = gets.chomp
also tried .kind_of? but didn't work
if num.is_a? Float
print " Number is in float "
also tried .kind_of? but didn't work
else num.is_a? Integer
print " Number is in integer "
end
Your problem here is that gets returns a String you can actually determine this based on the fact that you are chaining String#chomp, which removes the trailing "separator" which by default is return characters (newlines) e.g.
num = gets.chomp # User enters 1
#=> "1"
In order to turn this String into a Numeric you could explicitly cast it via to_i or to_f however you are trying to determine which one it is.
Given this requirement I would recommend the usage of Kernel#Integer and Kernel#Float as these methods are strict about how they handle this conversion. knowing this we can change your code to
print " Enter Value "
num = gets.chomp
if Integer(num, exception: false)
puts "#{num} is an Integer"
elsif Float(num, exception: false)
puts "#{num} is a Float"
else
puts "#{num} is neither an Integer or a Float"
end
Note: the use of exception: false causes these methods to return nil if the String cannot be converted to the desired object, without it both methods will raise an ArgumentError. Additionally when I say these methods are strict about conversion a simple example would be Integer("1.0") #=> ArgumentError because while 1 == 1.0, 1.0 itself is a Float and thus not an Integer
Some examples:
num = 6.6
num.is_a?(Integer)
=> false
num.is_a?(Float)
=> true
num = 6
num.is_a?(Integer)
=> true
num.is_a?(Float)
=> false
Minor note, #print is not the correct method to print to the screen. The correct method is #puts.
So your code would look like this:
if num.is_a?(Float)
puts 'Number is a float.'
elsif num.is_a?(Integer)
puts 'Number is an integer.'
else
puts 'Number is neither a float nor an integer.'
end
I suspect #gets returns a string though, which means you'll need to convert from a string into a numeric first.
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.
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
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
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.
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
"12".match(/^(\d)+$/) # true
"1.2".match(/^(\d)+$/) # false
"dfs2".match(/^(\d)+$/) # false
"13422".match(/^(\d)+$/) # true
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
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.
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?
A much simpler way could be
/(\D+)/.match('1221').nil? #=> true
/(\D+)/.match('1a221').nil? #=> false
/(\D+)/.match('01221').nil? #=> true
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.
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.
def isint(str)
return !!(str =~ /^[-+]?[1-9]([0-9]*)?$/)
end
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 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.
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 named integer? on any String object.
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
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 :)
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.
The fact that TypeOfClass === TypeOfClass is false strikes me as counter-intuitive. In the following code, even if field.class is the same class, it evaluates to false:
case field.class
when Fixnum, Float
field + other_field
when Date, DateTime, Time
field
else
puts 'WAT?'
end
I did this:
Fixnum === Fixnum # => false
Class === Class # => true
I found another thread:
Integer === 3 # => true
Fixnum === 3 # => true
3.class # => Fixnum
I fail to find a reason for this language design. What were the language designers thinking when they baked in this behavior?
I think this is relevant to the answer provided in another thread. It is not unnatural to assume that Numeric === Integer since an Integer is a more specific type of Numeric. But, it isn't:
Numeric === Integer #=> false
I think case statements or === requires caution. If this operator is what we think it is , then, a Numeric should be a Numeric, an Integer should be a Numeric, etc.
Does anyone have an explanation of why this feature doesn't extend to classes? It seems like it would be easy enough to return true if the compared class is a member of the class' ancestors.
Based on an answer submitted below, the code was originally classifying Time (as extended by ActiveSupport:CoreExtensions::Integer::Time and ActiveSupport:CoreExtensions::Float::Time):
Timeframe = Struct.new(:from, :to) do
def end_date
case self.to
when Fixnum, Float
self.from + self.to
when Date, DateTime, Time
self.to
else
raise('InvalidType')
end
end
end
and in the console, I get:
tf = Timeframe.new(Time.now, 5.months)
# => #<struct Timeframe from=Tue Dec 10 11:34:34 -0500 2013, to=5 months>
tf.end_date
# => RuntimeError: InvalidType
# from timeframe.rb:89:in `end_date'
I do not really see the problem here. For classes, the case equality operator asks whether the left hand argument is an instance of the class (or any subclass). So Fixnum === Fixnum really asks: "Is the Fixnum class itself a subclass of Fixnum?" No it is not.
Is the class Class itself a class? Class === Class, yes it is.
The point of the operator is that you should not need to go look for the class. What is wrong with using the case statement without the .class method in the beginning?
case field
when Fixnum, Float
field + other_field
when Date, DateTime, Time
field
else
puts 'WAT?'
end
If you have a more complex example you can write your own lambdas to make the case statement easier:
field_is_number = -> x {[Fixnum, Float].include? x.class}
field_is_time = -> x {[Date, DateTime, Time].include? x.class}
case field.class
when field_is_number
field + other_field
when field_is_time
field
else
puts 'WAT?'
end
That's Module#=== and its intended behavior:
mod === obj → true or false
Case Equality—Returns true if anObject is an instance of mod or one of
mod’s descendants. Of limited use for modules, but can be used in case
statements to classify objects by class.
It simply returns obj.kind_of? mod:
Fixnum === Fixnum #=> false
Fixnum.kind_of? Fixnum #=> false
Class === Class #=> true
Class.kind_of? Class #=> true
String === "foo" #=> true
"foo".kind_of? String #=> true
3 is both, an Integer and a Fixnum because of its class hierarchy:
3.kind_of? Integer #=> true
3.kind_of? Fixnum #=> true
3.class.ancestors #=> [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject]
Numeric is not an Integer, it's a Class:
Numeric.kind_of? Integer #=> false
Numeric.kind_of? Class #=> true
But 3, (2/3) and 1.23 are all Numeric:
3.kind_of? Numeric #=> true
Rational(2, 3).kind_of? Numeric #=> true
1.23.kind_of? Numeric #=> true
Bottom line: for case statements, just use case obj instead of case obj.class.
Update
You are getting this error because 5.months doesn't return an Integer, but a ActiveSupport::Duration:
Integer === 5.months #=> false
ActiveSupport::Duration === 5.months #=> true
Calling your method with 5.months.to_i or adding ActiveSupport::Duration to your classes should fix it.
If one of the operands is a class, it is checking whether the second one is this class instance. If they are both classes it will return false unless at least one of them is Class.
Note that Class is both a class and an instance of itself - it's probably biggest ruby weird TBH, but it makes perfect sense.
The reason I would vote for keeping this logic is that we can write those nice case statements without adding .class to objects.
Summary:
ClassName === object <=> object.kind_of? ClassName
However, if you really want to override this use:
class Class
def ===(object)
return object == self if object.is_a? Class
super
end
end
I need a class that can represent probabilities. It can be represented like a float between 0 and 1, and anything below 0.5 should evaluate to false. (or it can be between 1 and -1, anything negative is false)
p = A.probability()
puts p # will output 0.3
if(p)
puts 'success'
else
puts 'failure'
end
# will outputs 'failure'
From this post it seems to suggest it is possible: every object has a boolean value... Most objects in Ruby will have a boolean value of true. Only two objects have a boolean value of false. Just that I need to set this boolean value somehow. So is this possible?
I wanted to do something similar, but unfortunately this is not possible in Ruby.
The only two objects that have a boolean value of false are false itself and nil. A few weeks ago I had a an internet chat (IRC) discussion with Brixen, one of the main developers of rubinius, and he explained it pretty well. My understanding is that when Ruby decides whether an object is true or not, it does NOT call any methods on (i.e. send any messages to) the object, it simply looks at the pointer it has to the object to see whether the pointer itself is equal to false or nil. Since it doesn't call any methods on the object, there is no way for you to change the behavior.
The best you can do is something like this:
p = A.probability()
puts p # => 0.3
if p.to_bool
puts 'success'
else
puts 'failure'
end
There is no "cast to boolean" operator because, as David notes, falsiness is hard wired for false and nil and anything that isn't "falsy" is true. However, there is a logical negation operator so you can do it if you don't mind an explicit cast to boolean:
class P
attr_accessor :p
def !#
p < 0.5
end
end
And then:
>> p = P.new
>> p.p = 0.75
=> puts 'Pancakes!' if(!!p)
Pancakes!
>> p.p = 0.25
>> puts 'Pancakes!' if(!!p)
# No pancakes for you
All the double bangs might be a bit ugly but, on the upside, it might make people notice that something a little non-standard is going on.
First of all, you do not need a Float subclass. Those interested in subclassing Numeric types can see Katzuda's answer.
The simple way to achieve what you want to achieve is to simply use a method:
class P
def initialize p; #p = p
raise "outta range" unless 0 <= #p and #p <= 1 end
def success?; SUCC <= #p end
def fail?; not success? end
end
p = P.new 0.3
p.success? # => false
p.fail? # => true
q = P.new 0.7
q.success? # => true
q.fail? # => false
Remember, for these kind of circumstances, Ruby has methods.
I have a string, say '123', and I want to convert it to the integer 123.
I know you can simply do some_string.to_i, but that converts 'lolipops' to 0, which is not the effect I have in mind. I want it to blow up in my face when I try to convert something invalid, with a nice and painful Exception. Otherwise, I can't distinguish between a valid 0 and something that just isn't a number at all.
EDIT: I was looking for the standard way of doing it, without regex trickery.
Ruby has this functionality built in:
Integer('1001') # => 1001
Integer('1001 nights')
# ArgumentError: invalid value for Integer: "1001 nights"
As noted in answer by Joseph Pecoraro, you might want to watch for strings that are valid non-decimal numbers, such as those starting with 0x for hex and 0b for binary, and potentially more tricky numbers starting with zero that will be parsed as octal.
Ruby 1.9.2 added optional second argument for radix so above issue can be avoided:
Integer('23') # => 23
Integer('0x23') # => 35
Integer('023') # => 19
Integer('0x23', 10)
# => #<ArgumentError: invalid value for Integer: "0x23">
Integer('023', 10) # => 23
This might work:
i.to_i if i.match(/^\d+$/)
Also be aware of the affects that the current accepted solution may have on parsing hex, octal, and binary numbers:
>> Integer('0x15')
# => 21
>> Integer('0b10')
# => 2
>> Integer('077')
# => 63
In Ruby numbers that start with 0x or 0X are hex, 0b or 0B are binary, and just 0 are octal. If this is not the desired behavior you may want to combine that with some of the other solutions that check if the string matches a pattern first. Like the /\d+/ regular expressions, etc.
Another unexpected behavior with the accepted solution (with 1.8, 1.9 is ok):
>> Integer(:foobar)
=> 26017
>> Integer(:yikes)
=> 26025
so if you're not sure what is being passed in, make sure you add a .to_s.
I like Myron's answer but it suffers from the Ruby disease of "I no longer use Java/C# so I'm never going to use inheritance again". Opening any class can be fraught with danger and should be used sparingly, especially when it's part of Ruby's core library. I'm not saying don't ever use it, but it's usually easy to avoid and that there are better options available, e.g.
class IntegerInString < String
def initialize( s )
fail ArgumentError, "The string '#{s}' is not an integer in a string, it's just a string." unless s =~ /^\-?[0-9]+$/
super
end
end
Then when you wish to use a string that could be a number it's clear what you're doing and you don't clobber any core class, e.g.
n = IntegerInString.new "2"
n.to_i
# => 2
IntegerInString.new "blob"
ArgumentError: The string 'blob' is not an integer in a string, it's just a string.
You can add all sorts of other checks in the initialize, like checking for binary numbers etc. The main thing though, is that Ruby is for people and being for people means clarity. Naming an object via its variable name and its class name makes things much clearer.
I had to deal with this in my last project, and my implementation was similar, but a bit different:
class NotAnIntError < StandardError
end
class String
def is_int?
self =~ /^-?[0-9]+$/
end
def safe_to_i
return self.to_i if is_int?
raise NotAnIntError, "The string '#{self}' is not a valid integer.", caller
end
end
class Integer
def safe_to_i
return self
end
end
class StringExtensions < Test::Unit::TestCase
def test_is_int
assert "98234".is_int?
assert "-2342".is_int?
assert "02342".is_int?
assert !"+342".is_int?
assert !"3-42".is_int?
assert !"342.234".is_int?
assert !"a342".is_int?
assert !"342a".is_int?
end
def test_safe_to_i
assert 234234 == 234234.safe_to_i
assert 237 == "237".safe_to_i
begin
"a word".safe_to_i
fail 'safe_to_i did not raise the expected error.'
rescue NotAnIntError
# this is what we expect..
end
end
end
someString = "asdfasd123"
number = someString.to_i
if someString != number.to_s
puts "oops, this isn't a number"
end
Probably not the cleanest way to do it, but should work.
Re: Chris's answer
Your implementation let's things like "1a" or "b2" through. How about this instead:
def safeParse2(strToParse)
if strToParse =~ /\A\d+\Z/
strToParse.to_i
else
raise Exception
end
end
["100", "1a", "b2", "t"].each do |number|
begin
puts safeParse2(number)
rescue Exception
puts "#{number} is invalid"
end
end
This outputs:
100
1a is invalid
b2 is invalid
t is invalid