15

I have a string which is passed as a parameter to a function. Here, I want to check if the string contains only numbers. So I had a check like below:

def check_string(string)
  result = false
  if string.to_i.to_s.eql? string
    result =  true
  end
  result
end

But the problem arises when a string starts with 0. In that case, a false is returned.

check_string('123')  #=> true
check_string('0123') #=> false

How can I solve this issue?

Stefan
  • 109,145
  • 14
  • 143
  • 218
Palak Chaudhary
  • 181
  • 1
  • 1
  • 13

8 Answers8

43

You can try the following

def check_string(string)
  string.scan(/\D/).empty?
end

It would be truthy if string contains only digits or if it is an empty string. Otherwise returns false.

rmcsharry
  • 5,363
  • 6
  • 65
  • 108
Aleksey
  • 2,289
  • 17
  • 27
  • 4
    This is smart. You can also go with a variation of your answer and @Stefan's suggestion `string.scan(/^\d+$/).any?` which reads quite nicely I think. – Sagar Pandya Sep 28 '16 at 12:24
  • As for me the answer as it is now is more first-look-understandable ;) Just looking for nondigit symbol. If there isn't one - check has passed. – Aleksey Sep 28 '16 at 12:57
6

A number can be negative, or a float. So if these are allowed, consider this solution:

def is_numberic?(str)
    str == "#{str.to_f}" || str == "#{str.to_i}"
end

some input which evaluate to true

pry(main)> is_numberic? '5'
=> true
pry(main)> is_numberic? '58127721'
=> true
pry(main)> is_numberic? '58127721.737673'
=> true
pry(main)> is_numberic? '0'
=> true
pry(main)> is_numberic? '1818'
=> true
pry(main)> is_numberic? '0.1'
=> true
pry(main)> is_numberic? '0.0'
=> true
pry(main)> is_numberic? '11.29'
=> true
pry(main)> is_numberic? '-0.12'
=> true
pry(main)> is_numberic? '-29'
=> true

the input which evaluate to false

pry(main)> is_numberic? '10 years'
=> false
pry(main)> is_numberic? '01'
=> false
pry(main)> is_numberic? '00'
=> false
pry(main)> is_numberic? '0.10'
=> false
pry(main)> is_numberic? ''
=> false

As you can see, there're several cases which probably should be supported, eg '0.10', but are not. In this case, the permitted input is '0.1'.

Zack Xu
  • 11,505
  • 9
  • 70
  • 78
5
def check_string(str)
  str !~ /\D/
end

check_string '123'
  #=> true
check_string ''
  #=> true
check_string '1a2'
  #=> false
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
2

this is my proposition for detecting if it's a float number

def check(string)
  scan = string.scan(/\D/)
  scan.size == 0 || (scan.size == 1 && scan.first == ".") # or "," depend on your separator
end

example of use:

check("123") => true
check("12.3") => true
check("12e3") => false
check("12.3.2") => false

EDIT: 2023 After some years i see this is the most compact solution:

def check_string(str)
  str.scan(/\D/).empty?
end
Kaiizer
  • 61
  • 6
1

You can use Regexp for it:

def check_string(string)
  raise 'Empty string passed' if string.empty?

  /\A\d+\z/ === string
end

check_string '123'
#=> true
check_string '0123'
#=> true
check_string '0'
#=> true
Andrey Deineko
  • 51,333
  • 10
  • 112
  • 145
1

We can also use the "match" function to do this.

"1234".match(/\D/)
#=> nil
"1234foo".match(/\D/)
#=> #<MatchData "f">

match (String) - APIdock

Tilak M Divakar
  • 101
  • 1
  • 5
0

I think we should use the regex to find this.

it will work for the below scenarios
"3.0"
"av3"
"3"

is_numeric = false if option.option.match?(/[^0-9.]/)

Iqbal Khan
  • 4,587
  • 8
  • 44
  • 83
-2

If anyone is searching for another way to determine if string is numeric -> is to use "is_a? Numeric". Is_a? reference documentation

"namaste".is_a? Numeric
=> false

6.is_a? Numeric
=> true

str1 = "foo"
str2 = 9

str1.is_a? Numeric
=> false
str2.is_a? Numeric
=> true

You can also use:

7.is_a?(Numeric)
=> true

"too".is_a?(Numeric)
=> false

Basically it's determining if a class is a type of class object. I just found this and thought I would share.

Chnikki
  • 464
  • 1
  • 5
  • 8
  • 2
    Your `str2` is not a string. Try this with `str2 = "9"` and see if it works (It does not). – IMP1 Mar 19 '20 at 15:15