freshest
freshest

Reputation: 6241

Regex - Cost of an Item

What is the regular expression to check a cost has been provided correctly:

Possible matches are:

9 | 23.3 | 25.69

Not allowed:

  1. | 2.

Upvotes: 2

Views: 515

Answers (6)

Wayne Conrad
Wayne Conrad

Reputation: 108109

Since you're in Rails, you might be better served using validates_numericality_of in your model:

validates_numericality_of :cost, :greater_than_or_equal_to => 0.01, 
                                 :less_than_or_equal_to => 0.99

To prevent fractional pennies, use this in conjunction with validates_format_of:

validates_format_of :cost, :with => /\A\d*(\.\d{1,2})?\Z/

This leverages the strength of each validation.

Upvotes: 0

Tim Pietzcker
Tim Pietzcker

Reputation: 336418

Of course, the correct way would be to take the provided string, convert it to a number (catching errors if it's not a parseable number) and then compare that with the valid values.

If it has to be a regex, it's of course possible but ugly:

^(?:[1-9][0-9]?(?:\.[0-9]{1,2})?|0?.0[1-9]|0?.[1-9][0-9]?)$

Explanation:

^                   # start of string
(?:                 # either match
 [1-9][0-9]?        # a number between 1 and 99
 (?:\.[0-9]{1,2})?  # optionally followed by a decimal point and up to two digits
|                   # or
 0?.0[1-9]          # a number between 0.01 and 0.09 (optionally without leading 0)
|                   # or
 0?.[1-9][0-9]?     # a number between 0.1 and 0.99
)                   # end of alternation
$                   # end of string

Of course, in most regex dialects, you can use \d in place of [0-9] without a change in meaning, but I think in this case sticking to the longer version helps readability.

In Ruby, assuming your input string never contains a newline:

if subject =~ /^(?:[1-9][0-9]?(?:\.[0-9]{1,2})?|0?.0[1-9]|0?.[1-9][0-9]?)$/
    # Successful match
else
    # Match attempt failed
end

Since you care about the number of significant digits, another solution would be to first check if the input looks like a number, and if it passes that test, convert it to a float and check if it's in range.

^(\d{1,2}|\d{0,2}\.\d{1,2})$

would match any number (integer or decimal up to two digits after the decimal point) between 0 and 99.99. Then you just need to check whether the number is >= 0.01. The advantage of this approach is that you can easily extend the range of digits allowed before/after the decimal point if the requirements for valid numbers change, and then adjust the value check accordingly.

Upvotes: 2

Ed.
Ed.

Reputation: 1952

It's not the best but works

(0\.01|0\.02|0\.03| ... |99\.98|99\.99)

Upvotes: 0

Zano
Zano

Reputation: 2761

A solution using a regexp would be hard to maintain since it is a very strange and unintuitive way to solve the problem. It would be hard for anyone reading your code (including yourself in a couple of weeks) to understand what the purpose of the check is.

That said, assuming values 0.00 - 99.99 are valid, the regexp could be

^\d{0,2}(\.\d\d?)?$

Assuming 0.01 - 99.99, it's a bit more complicated:

^0{0,2}(\.(0[1-9]|[1-9]\d?))?|\d{0,2}(\.\d\d)?$

And don't get me started on 0.02 - 99.98... :-)

So basically, don't do this. Convert the string to a numerical value and then do a regular interval check.

Upvotes: 2

Stephan Schinkel
Stephan Schinkel

Reputation: 5540

try

^\d{1,2}(\.\d{1,2})?$  

it checks whether there are 1 or 2 digits and optionally if there is a dot it checks if there are 1 or 2 digits after the dot.

as answer to the comments of your question: nothing speaks against checking for the format before sending the request to a server or something else. range checks could be done somewhere else.

Upvotes: 0

Sachin Shanbhag
Sachin Shanbhag

Reputation: 55499

I am not sure you need to do this using regular expression why dont you just split the string on '|' into an array and check each element in array is greater than 0.01 and less than 99.99

Upvotes: 2

Related Questions