I am trying to write a regex for allowing 3 digit numbers followed by optional decimal, integer part cant be greater than 180 or smaller than -180. example of valid enteries are 156.56, 56.778, 9, 6.7.etc etc.
So far I came up with this ^(\+|-)?:180|1开发者_如何学编程[0-7][0-9]|[0-9][0-9]|[0-9]?([\.][0-9]{1,3})?$
but these seems to match 195.678 too.
Instead of doing that, why not just have two checks? One makes sure that you match the pattern, and the other makes sure that the value is between -180 and 180.
/-?\d{3}(\.\d{1,3})?/.test(val) && (val <= 180 && val >= -180)
The resulting solution is far easier to understand and maintain, and not to mention, saner :).
The reason your regex doesn't work is that the ^
and $
don't match across the entire pattern. You have the different conditions in your regex that are separated by |
. The ^
is associated with the first option, and the $
is associated with the last option. This is easy to see in the following example:
Assume you had the regex /^[0-9][0-9]|[0-9]$/
. If you tested this against 12345
what would you get? You might be inclined to say that it would return false
, but it actually returns true
. This is because there is a valid match! The 12
in 12345
will match against ^[0-9][0-9]
. So what you're saying is that you want to match against any two numbers at the beginning of the string or against a number at the end of the string. Basically any string that has at least two numbers at the beginning or one number at the end, will match. So 12abc
will match, as will abc1
.
However, if you changed the regex to /^([0-9][0-9]|[0-9])$/
, only one and two-digit numbers will match. This is because the beginning and end-of-string anchors are outside the matching group, meaning the entire group has to match. This is something that you have to consider when you have conditions in your regex.
EDIT
Also, Tim points out:
... there is a colon where it shouldn't be: ^(+|-)?:180 matches :180, +:180 or -:180 and nothing else
Since you introduce the possibility of leading 0's, something like this
should validate the entire range:
^(?:\+|-)?(?:180(?:\.0{0,3})?|(?:0{1,3}|0{0,2}[1-9]|0?[1-9][0-9]|1[0-7][0-9])(?:\.[0-9]{1,3})?)$
test in Perl
use strict;
use warnings;
my $regex = qr/
^
(?:\+|-)?
(?:
180 (?:\.0{0,3})?
|
(?:
0{1,3}
|
0{0,2}[1-9]
|
0?[1-9][0-9]
|
1[0-7][0-9]
)
(?:\.[0-9]{1,3})?
)
$
/x;
for ('000' .. '180')
{
my $num;
$num = -1 * $_;
if ( $num =~ /$regex/) { print "$num\t" }
else { print "($num failed)\t" }
$num = 1 * $_;
if ( $num =~ /$regex/) { print "$num\t" }
else { print "($num failed)\t" }
$num = '+' . $_ . ".$_";
if ( $num =~ /$regex/) { print "$num\t" }
else { print "($num failed)\t" }
$num = '-' . $_ . ".$_";
if ( $num =~ /$regex/) { print "$num\t" }
else { print "($num failed)\t" }
print "\n";
}
Output:
0 0 +000.000 -000.000
-1 1 +001.001 -001.001
-2 2 +002.002 -002.002
-3 3 +003.003 -003.003
-4 4 +004.004 -004.004
-5 5 +005.005 -005.005
-6 6 +006.006 -006.006
-7 7 +007.007 -007.007
-8 8 +008.008 -008.008
-9 9 +009.009 -009.009
-10 10 +010.010 -010.010
-11 11 +011.011 -011.011
-12 12 +012.012 -012.012
-13 13 +013.013 -013.013
-14 14 +014.014 -014.014
-15 15 +015.015 -015.015
-16 16 +016.016 -016.016
-17 17 +017.017 -017.017
-18 18 +018.018 -018.018
-19 19 +019.019 -019.019
-20 20 +020.020 -020.020
-21 21 +021.021 -021.021
-22 22 +022.022 -022.022
<snipped>
-172 172 +172.172 -172.172
-173 173 +173.173 -173.173
-174 174 +174.174 -174.174
-175 175 +175.175 -175.175
-176 176 +176.176 -176.176
-177 177 +177.177 -177.177
-178 178 +178.178 -178.178
-179 179 +179.179 -179.179
-180 180 (+180.180 failed) (-180.180 failed)
精彩评论