play_ Posted August 19, 2009 Share Posted August 19, 2009 Hi. Looking for a regular expression that would match a price. (without $). So it would match: 10 10.99 1,099 1,099.49 So i guess the rule is, has to start with a number, has to end with a number, and can have one comma and/or one period in the middle Quote Link to comment Share on other sites More sharing options...
Garethp Posted August 19, 2009 Share Posted August 19, 2009 ~^([0-9]+(?:\.|,)?[0-9]+?$~ Quote Link to comment Share on other sites More sharing options...
nrg_alpha Posted August 19, 2009 Share Posted August 19, 2009 ~^([0-9]+(?:\.|,)?[0-9]+?$~ Of course, that pattern would fail if you encounter a value like 1,345,675.90 (since yours only allows a single comma or period). My example: setlocale(LC_CTYPE, 'C'); // ensure \d only matches 0-9 $price = array('10', '10.99', '1,099', '1,099.98', '1,34,5.68', '123.56.7', '3,454,579.9', '1,665.908'); foreach($price as $val){ echo (preg_match('#^\d+(?:,\d{3})*(\.)?(?(1)\d{1,2})$#', $val))? $val . " is valid!<br />\n" : $val . " is NOT valid!<br />\n"; } @play_, notice the final quantifying interval {1,2}... this would allow one or two digits after the decimal (if decimal is found). If you only want two digits after the decimal, simply change that interval to {2} Quote Link to comment Share on other sites More sharing options...
Garethp Posted August 19, 2009 Share Posted August 19, 2009 Why not just ~^([0-9]{1,3})((,|\.)[0-9]{3,3})*?(\.[0-9]{1.2}$~ That way you have 1 - 3 numbers in the front, and then possible a comma or dot followed by three numbers, which is a repitive optional, with an option two decimal number at the end? When I say why not, I'm not trying to one up you, I'm just trying to see if there's something wrong with my RegEx, I'm still kinda new at it Quote Link to comment Share on other sites More sharing options...
nrg_alpha Posted August 19, 2009 Share Posted August 19, 2009 Why not just ~^([0-9]{1,3})((,|\.)[0-9]{3,3})*?(\.[0-9]{1.2}$~ That way you have 1 - 3 numbers in the front, and then possible a comma or dot followed by three numbers, which is a repetitive optional, with an option two decimal number at the end? When I say why not, I'm not trying to one up you, I'm just trying to see if there's something wrong with my RegEx, I'm still kinda new at it There are a few issues with your pattern. It looks for a digit (1-3 times), followed by a comma or dot, followed by a digit, 3 times (I'll get to your additional errors in a second).. so if I stop right there, that could in itself match 3.543,678.432,788 see the problem? The cluster of 3 digits can alternate between commas and dots.. Additional issues with this pattern include the following.. ((,|\.)[0-9]{3,3})*? Since you are using zero or more times, you don't need the ? to make it optional, as it is already optional (because it allows zero times) Also, keep in mind that every set of parenthesis creates a capture.. since we are looking for a format, we don't care about doing specific captures.. so when you have something like (,|\.), this is getting stored into an internal variable.. when dealing with stuff we don't want to capture, we can resort to non-capture groups, which take on the format (?: .... ). In my pattern in my previous post, I make use of only 1 capture (the decimal), and if that decimal is there, then it must follow 1 or 2 digits. Earlier in my pattern, you'll notice (?:,\d{3})* which groups a comma followed by 3 digits, all of which is zero or more times.. but I don't care about storing this into an internal value.. so I use (?:,\d{3}) instead of (,\d{3}). [0-9]{3,3} intervals like that {3,3} can simply be stated as {3}. When there is two values involved, the first is a minimum, the second a maximum.. so in this case, you are saying 3 minimum, 3 maximum.. by only stating a single value, this says, I want an x amount only (so {3} means look for something 3 consecutive times). (\.[0-9]{1.2} there are two issues with this... a) there is no closing parenthesis.. b), your interval is using a dot instead of a comma to separate min and max values. Quote Link to comment Share on other sites More sharing options...
nrg_alpha Posted August 19, 2009 Share Posted August 19, 2009 Granted, I did realize I botched the beginning of my pattern because of \d+... so my pattern should be more like: #^\d{1,3}(?:,\d{3})*(\.)?(?(1)\d{2})$# Quote Link to comment Share on other sites More sharing options...
play_ Posted August 19, 2009 Author Share Posted August 19, 2009 Thanks to both for replying. neg_alpha, i am using yours, without setlocale function. seems to work fine without it. Quote Link to comment Share on other sites More sharing options...
nrg_alpha Posted August 19, 2009 Share Posted August 19, 2009 Yeah, the setlocale was just incase.. (odds are, you won't have to deal with any additional stuff like exponents.. just a habit I have when dealing with short hand character classes), so it shouldn't be an issue without it. Sorry I botched my initial pattern... its 2:30am here.. Im tired. Quote Link to comment Share on other sites More sharing options...
play_ Posted August 19, 2009 Author Share Posted August 19, 2009 it is late and thanks again. works beautifully. Quote Link to comment Share on other sites More sharing options...
Garethp Posted August 19, 2009 Share Posted August 19, 2009 Why not just ~^([0-9]{1,3})((,|\.)[0-9]{3,3})*?(\.[0-9]{1.2}$~ That way you have 1 - 3 numbers in the front, and then possible a comma or dot followed by three numbers, which is a repetitive optional, with an option two decimal number at the end? When I say why not, I'm not trying to one up you, I'm just trying to see if there's something wrong with my RegEx, I'm still kinda new at it There are a few issues with your pattern. It looks for a digit (1-3 times), followed by a comma or dot, followed by a digit, 3 times (I'll get to your additional errors in a second).. so if I stop right there, that could in itself match 3.543,678.432,788 see the problem? The cluster of 3 digits can alternate between commas and dots.. Additional issues with this pattern include the following.. ((,|\.)[0-9]{3,3})*? Since you are using zero or more times, you don't need the ? to make it optional, as it is already optional (because it allows zero times) Also, keep in mind that every set of parenthesis creates a capture.. since we are looking for a format, we don't care about doing specific captures.. so when you have something like (,|\.), this is getting stored into an internal variable.. when dealing with stuff we don't want to capture, we can resort to non-capture groups, which take on the format (?: .... ). In my pattern in my previous post, I make use of only 1 capture (the decimal), and if that decimal is there, then it must follow 1 or 2 digits. Earlier in my pattern, you'll notice (?:,\d{3})* which groups a comma followed by 3 digits, all of which is zero or more times.. but I don't care about storing this into an internal value.. so I use (?:,\d{3}) instead of (,\d{3}). [0-9]{3,3} intervals like that {3,3} can simply be stated as {3}. When there is two values involved, the first is a minimum, the second a maximum.. so in this case, you are saying 3 minimum, 3 maximum.. by only stating a single value, this says, I want an x amount only (so {3} means look for something 3 consecutive times). (\.[0-9]{1.2} there are two issues with this... a) there is no closing parenthesis.. b), your interval is using a dot instead of a comma to separate min and max values. So how about ~^((?:[0-9]{1,3})(?:,[0-9]{3})*(?:\.[0-9]{1,2}))$~ Would that work? And as for capturing the data, he just said match, didn't he? Still, my above one should match the price as a number if I wrote it properly Quote Link to comment Share on other sites More sharing options...
nrg_alpha Posted August 19, 2009 Share Posted August 19, 2009 So how about ~^((?:[0-9]{1,3})(?:,[0-9]{3})*(?:\.[0-9]{1,2}))$~ Would that work? And as for capturing the data, he just said match, didn't he? Still, my above one should match the price as a number if I wrote it properly Would it work? You could always try it yourself on an array of possible combinations of dollar figures (as I have done with my example). It would almost work. The first and second groups work... (?:[0-9]{1,3})(?:,[0-9]{3})* but the last part - (?:\.[0-9]{1,2}) doesn't, because after the initial 3 digits in the number, whether the middle part exists or not [referring to (?:,[0-9]{3})*], the final part requires a decimal, followed by one or two digits. That last part could have the ? quantifier. While you have done better with non capturing, you have encased the entire pattern in a capture (the very first and outer last parenthesis is not necessary). Also, you don't need to put a non capturing group on (?:[0-9]{1,3}) at the start, as this sequence is already required.. so one possible version based on yours could be (untested): ~^[0-9]{1,3}(?:,[0-9]{3})*(?:\.[0-9]{1,2})?$~ That way, after the first initial 3 digits, both second and last chunks are optional. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.