Hello, I would like to match with RegExp a number between X and Y. Is that possible?
([0-9]+) will match any number, how could I do to match a number between, for instance, 110 and 2234?
Hello, I would like to match with RegExp a number between X and Y. Is that possible?
([0-9]+) will match any number, how could I do to match a number between, for instance, 110 and 2234?
This is not the sort of thing regexes excel at. You will probably find it easier to ensure that you have the right number of digits /^([0-9]{3,4})$/
and then do further checks against the capture.
It's possible allbeit not pretty.
\b(?:[1][1][0-9]|1\d{3}|223[0-4]|2[0-1]\d\d|2[0-2][0-3][0-4])\b
I emailed Phillip Hazel, the author of PCRE, in 2006 what he thought of math's in regex:
Perhaps this lies out of the scope of the project in your view: The ability to treat numbers as being numbers and not text, this would definitely be a worthwhile feature. Allowing you to do some basic math checks on matched digits, like: is the 2nd matched digit higher or lower, is the third digit a multiple off the 1st, and many more complicated cases I won't elaborate on just to get my point accross. Do you feel this exceeds the realm of textmatching?
to which I got the following reply:
Yes, I think I do, and also, it is not something that is available in Perl regular expressions. I know that PCRE does have some extensions from Perl, but nothing as major as that (you could perhaps hack something up using callouts, but that would be a bit ad hoc, and no doubt exceedingly messy!).
Philip
and I couldn't agree more now in `09. Just match all numbers and do number validation in whatever language you're doing the matching with.
According to Generate a Regular Expression to Match an Arbitrary Numeric Range, and after generating such a regex for your example at Regex_For_Range:
\b0*(1[1-9][0-9]|[2-9][0-9]{2}|1[0-9]{3}|2[01][0-9]{2}|22[0-2][0-9]|223[0-4])\b
would do the trick.
The process would be (still following that Regex generator):
First, break into equal length ranges:
110 - 999
1000 - 2234
Second, break into ranges that yield simple regexes:
110 - 199
200 - 999
1000 - 1999
2000 - 2199
2200 - 2229
2230 - 2234
Turn each range into a regex:
1[1-9][0-9]
[2-9][0-9]{2}
1[0-9]{3}
2[01][0-9]{2}
22[0-2][0-9]
223[0-4]
Collapse adjacent powers of 10: 1[1-9][0-9] [2-9][0-9]{2} 1[0-9]{3} 2[01][0-9]{2} 22[0-2][0-9] 223[0-4]
Combining the regexes above yields:
0*(1[1-9][0-9]|[2-9][0-9]{2}|1[0-9]{3}|2[01][0-9]{2}|22[0-2][0-9]|223[0-4])
Next we'll try factoring out common prefixes using a tree:
Parse into tree based on regex prefixes:
. 1 [1-9] [0-9]
+ [0-9]{3}
+ [2-9] [0-9]{2}
+ 2 [01] [0-9]{2}
+ 2 [0-2] [0-9]
+ 3 [0-4]
Turning the parse tree into a regex yields:
0*(1([1-9][0-9]|[0-9]{3})|[2-9][0-9]{2}|2([01][0-9]{2}|2([0-2][0-9]|3[0-4])))
We choose the shorter one as our result.
\b0*(1[1-9][0-9]|[2-9][0-9]{2}|1[0-9]{3}|2[01][0-9]{2}|22[0-2][0-9]|223[0-4])\b
Thanks all for your comments and replies. You've all been very kind :-)
Note: I need and regexp because i'm using it in .htaccess file for match documents.
Thanks.
While you could do it with some absurd looking regex (as VonC answered), regex really isn't supposed to do this.. Why not defer the number checking to the redirected-to-script?
If numbers 110-2234 go to script1, and 1-109 go to script2, it would be much simpler to direct all numbers at a router
script, and have it redirect to the correct location (via HTTP redirects)..
In .htaccess
:
RewriteRule ^view/([0-9]+)/?$ router.php?page=$1 [L]
..then in router.php
, something like:
<?PHP
if(
int($_GET['page']) > 110 &&
int($_GET['page']) < 2234
){
header("Status: 301 Moved Permanently\nLocation: /script1");
}else{
header("Status: 404 Not Found");
}
?>