tags:

views:

639

answers:

4

I'm trying to figure out how to check if a string matches a regular expression, but I want to know if the entire string matches just once. Here's my code but it seems absurdly long

def single_match(test_me, regex)
  ret_val = false
  test = regex.match(test_me)
  if (test.length==1 && test[0].length == test_me.length)
      ret_val = true
  end
  return ret_val
end

is there an easier way to do this?

P.S. Here's the method I'm really trying to write, since people always seem to ask why I want the gun these days:

def is_int(test_me)
  return single_match(test_me, /[0-9]*/)
end

Edit Thanks everybody. Here's where I'm really using it, but this regex stuff is always interesting to go through. Thanks for the great and educational answers.

+2  A: 

This?

def single_match(str, regex)
  str.match(regex).to_s == str
end
Zach Langley
Yeah, this is why I wanted to learn Ruby... THANKS!
Yar
+7  A: 

You don't need to do this, your method can be replaced by using the regular expression of /^[0-9]*$/. The ^ tells it match start of a line and $ tells it match end of the line. So it will match: start of line, 0 to any in range of 0 to 9, and finally end of line.

def is_int(test_me)
  test_me =~ /^[0-9]*$/
end

And you don't need the return statements, Ruby implicitly returns the last statement.

Edit:

It probably would be easier and look better to use the to_i instance method of String class.

def is_int(test_me)
  test_me.to_i.to_s == test_me
end

Edit: (did some tests)

Comparing the performance between the two methods shows that .to_i.to_s == way is 5% faster. So it is up to personal preference to which ever looks better and if you want to handle leading zeroes.

Samuel
+1, this is the better way to do it.
Zach Langley
Regex! I like your answer and Zach Langley's answer too... THANKS.
Yar
That will match the empty string too. Consider /^\d+$/
PEZ
That could be a good or bad thing. Since he used * in his question, I used it to. He may want an empty string to be seen as a number (0).
Samuel
Or even /^[+-]?\d+$/
PEZ
@Samuel: Yes, that's why I said "consider".
PEZ
Was that a copy and paste, or parallel evolution?
DanSingerman
The former doesn't handle negatives and will match an empty string (but consider PEZ's recommendations). I'd say HermanD's solution is much more elegant.
Zach Langley
@Pez, yeah, didn't think of empty String.
Yar
Samuel, just 9 months later or so, this answer still works :)
Yar
+3  A: 

To do what you really want should be even simpler

def is_int(test_me)
  test_me.to_i.to_s == test_me
end
DanSingerman
I'm glad I put my real question in there, just in case! Thanks...
Yar
This won't work with leading 0's, but will work with negatives. +1
Zach Langley
I guess you could argue that integers shouldn't have leading zeroes (assuming that's what the function is trying to determine)
DanSingerman
Thanks Zach, for my purposes without leading zeroes is okay, but still... the to_i can't figure it out? Weird...
Yar
"0000123".to_i gives 123 - which makes sense to me. Hence the comparison fails when you turn that back into a string
DanSingerman
I get it, HermanD... interesting. But as everyone has pointed out to me, I shouldn't be doing type conversions like this anyway, so I guess it's fine...
Yar
+1  A: 

To answer your original question, for the sake of people finding this page in a search, "scan" will return an array of matches, so if you want to find out how many times some regexp matches, e.g. how many runs of digits there are, you can do:

mystring.scan(/\d+/).size
glenn mcdonald
You would then know how many RUNS of digits there are, but not whether they occupy the whole string (which was the question) or some part of it. Hence setting mystring to "3332b" is the same as "3" with your scanning regex.
Yar
Ah, ambiguity in the phrase "the entire string matches just once": "there is only one match anywhere in the string" vs "the string is a complete match"...
glenn mcdonald
Thanks Glenn, I was never informed of your comment, excellent point.
Yar