tags:

views:

46

answers:

5

I need a regex that will match on a price or amount.

It should match on these

  • 100
  • 410.00
  • 0.12

but not these

  • 100.000
  • -600.00
  • .12
  • .1234

This works for all of the above cases except for single values like 1

/^[0-9]*\.?[0-9]{2}+$/

How can I adjust it so single integers will match? And can anyone explain why the current one is wrong?

+2  A: 

Make the fractional part optional:

/^[0-9]+(\.[0-9]{2})?$/
cam
Just realised you answered first. Thanks!
kidrobot
+1  A: 

The regular expression you've entered will match the following:

Any digit, 0 or more times, followed by, a dot, 0 or 1 time, followed by exactly 2 digits

So the regular expression will certainly always require at least 2 digits due to the end bit.

I'd suggest the following:

/^[0-9]+(\.[0-9]{2})?$/

Which will match 1 or more digits, optionally followed by a dot and exactly 2 digits.

Tom Revell
Perfect. Thanks, Tom!
kidrobot
@kidrobot: you should accept Tom's solution since it worked for you
cam
+1  A: 

I think you'd be better off leaving regular expressions out of the mix.

What I would do is convert the value to an int and round off the decimal, then check if it's negative. I would also check whether the first character is a dollar sign and, if so, just remove it. The code would be simpler and more readable that way IMO, and if someone did enter 12.34512 or .1, the system would still work.

//untested

$amount = "$0.12"
if( $amount && $amount[0] == '$' ) {
    ltrim($amount, '$');
}
$int_amount = (int) $amount;
$int_amount = round($int_amount, 2);
if( $amount <= 0 ) {
    //error
}

That being said, I don't know whether you have to use regexp for whatever reason (like if you have a validation function that takes a value and regexp as arguments), but in a case like this I think being liberal in the price format would be better so as not to tell users that they entered an "invalid amount" when they input 12 cents without a leading zero.

Carson Myers
Another function down the line is expecting the amount to be the kind displayed in a store or on a price tag so 12.34512 or .1 can't be allowed. But yes, I do wonder about the efficiency of regex sometimes.
kidrobot
yeah but the code I posted should take care of that, I think. 12.34512 would become 12.34, and .2 _should_ become 0.2 (when converted back into string. Maybe not implicitly, but it's not hard), though I could be mistaken. You could add more to make sure there's a trailing zero, too, IMO the effort is worth it to avoid confusing users. But in any case, it looks like you've got a solution already -- I'll just leave this here in case it helps someone else
Carson Myers
+1  A: 

I suggest a small correction to Tom Revell's regular expression since you could still input several 0's as first digits. ie 00002.23 which is most likely incorrect.

/^([1-9][0-9]*|0)(\.[0-9]{2})?$/
Guillaume Bodi
You are right. Good catch!
kidrobot
A: 

Best way to work out a regular expression is to start out by getting the idea down on paper. Try drawing your regex or writing it in some kind of pseudo code, test it in your head and make sure it's right before you get bogged down in your language's regex syntax.

Michael Clerx