简体   繁体   中英

Regex for Decimal Number with limits

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM