8

I am really new to and want know if it's possible to check if a string contains only positive numbers using or some other function?

str = "123abcd"  #return false because it contains alphabets
str = "153"      #return true because of all numbers
Mark Thomas
  • 37,131
  • 11
  • 74
  • 101
user3187131
  • 263
  • 1
  • 5
  • 14
  • 2
    By "positive digits", I presume you mean 1-9. Is that correct, or do you mean '0-9' (in which case you should strike "positive")? – Cary Swoveland Feb 16 '14 at 18:27
  • There is no such thing as "positive digits". One or more digits express(es) a number. A number can be positive or not. `0` by itself expresses a non-positive number. The `0` in `10` is part of a positive number. You cannot say whether `0` as a digit is positive or not. Similarly, `1` alone is a positive number. `1` in `-1` is part of a negative number. – sawa Feb 16 '14 at 20:22
  • 2
    I realized that the original question said "positive numbers" and Wayne edited to "positive digits". The original one was better. – sawa Feb 16 '14 at 20:40
  • Interesting. If that's the case, then all the solutions are wrong because of strings like "+15" or "2.0e+40" – Mark Thomas Feb 16 '14 at 20:48
  • @MarkThomas You are right. The question is actually a difficult one if that is what was intended. The question is not clear for sure. – sawa Feb 16 '14 at 20:56
  • Sloppily-worded questions like this one are time-wasting and annoying, doubly-so when the asker takes no action rectify the problem. – Cary Swoveland Feb 17 '14 at 01:24

5 Answers5

20

All other answers so far using regex are inefficient.

"123abcd" !~ /\D/ # => false
"153" !~ /\D/     # => true
sawa
  • 165,429
  • 45
  • 277
  • 381
5

Of course Regexp is good for this:

string = "123abcd"
/^(?<num>\d+)$/ =~ string
num # => nil

string = "123"
/^(?<num>\d+)$/ =~ string
num # => '123' # String

So if you need to check the condition:

if /^(?<num>\d+)$/ =~ string
   num.to_i # => 123
   # do something...
end

#to_i method of String isn't valid for your case because it will return a number, if string is even with letters:

string = "123abcd"
string.to_i # 123
Малъ Скрылевъ
  • 16,187
  • 5
  • 56
  • 69
4
if '123'.match(/^\d+$/)
  # code
end
Danil Speransky
  • 29,891
  • 5
  • 68
  • 79
  • It works, but is inefficient. – sawa Feb 16 '14 at 17:58
  • @sawa Can you explain why this is less efficient than your negated answer? – Mark Thomas Feb 16 '14 at 18:24
  • @MarkThomas When the string contains a non-digit, my regex does not need to carry the information of a matching candidate because (mis-)match is decided by looking at a single character. It just needs to increment the start position to apply the pattern. The regex in this answer has to keep track of the matching candidate information (sequence of digits) up to the point it fails. – sawa Feb 16 '14 at 18:43
  • @sawa I don't see how this needs to track anything, as there are no capture groups. As soon as you see a non-digit, this can fail. – Mark Thomas Feb 16 '14 at 18:46
  • @MarkThomas Having no capture group only means that it does not need to keep track of any substring of the match. But it needs to keep the entire match during the matching process in case it succeeds, even if it eventually turns out to fail. A matchdata object has the information of the entire matched string. – sawa Feb 16 '14 at 20:03
  • @sawa Ah, so you not are referring to the regex but the fact that the `match` method returns a MatchData object. Would `"123" =~ /^\d+$/` be better? – Mark Thomas Feb 16 '14 at 20:11
  • @MarkThomas Still in that case, the matchdata is kept in `$~`. – sawa Feb 16 '14 at 20:13
2

I' do using Regexp#=== as below :

str = "123abcd"
/^\d+$/ === str  # => false # because string not only contains digits
str = "153" 
/^\d+$/ === str  # => true  # because string only contains digits

update (considering @sawa's comment1 and comment2)

str = "123abcd"
/\D/ === str  # => true  # because string contains non-digit
str = "153" 
/\D/ === str  # => false # because string doesn't contain any non-digit
Community
  • 1
  • 1
Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
0

I originally answered this when "only positive digits" was a requirement, but I see that has been changed to "only positive numbers" (the original wording), which, in part because of the example given (which rules out the interpretation "12abc34" => true, "12abc-34" => false and does not suggest the interpretation "1.5abc" => true), I take to mean "one positive integer". My assumption is stated more precisely by my answer:

str =~ /^0*[1-9]\d*$/

This question raises another: "How many Rubiests can dance on the head of a pin?". Maybe it's just a slow-news day. Thanks to @sawa and @Mark for their comments.

Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
  • Logic error: returns `true` for an empty string. You want `+`. – Mark Thomas Feb 16 '14 at 18:33
  • 1
    @Mark, I mulled that, but decided to go with `*`, as I figured the asker did not mean "only positive digits" literally, for if/she did, one could argue that false should be returned for strings of length one, which I don't think was intended. Was the downvote yours? – Cary Swoveland Feb 16 '14 at 19:57
  • 1
    Yes, but I will remove it if you put your (completely valid) interpretation of the unstated requirements in the answer. – Mark Thomas Feb 16 '14 at 20:16
  • Even more fatal is the fact the no zero is allowed. It excludes numbers like `10`. The question originally said "positive numbers", and was edited by Wayne to "positive digits", which does not have clear meaning. – sawa Feb 16 '14 at 20:42
  • @sawa, I wasn't aware of the edit you mentioned, but will fix. Mark, thanks for the suggestion. Will do. – Cary Swoveland Feb 16 '14 at 21:47