Using regular expressions to validate a numeric range

后端 未结 11 1587
自闭症患者
自闭症患者 2020-11-21 22:16

My input number is an int. But the input number must be in a range from -2055 to 2055 and I want to check this by using regular expression.

So is there anyway to wri

相关标签:
11条回答
  • 2020-11-21 22:56

    Try this:

    ^-?0*(1?[0-9]{1,3}|20[0-4][0-9]|205[0-5])$
    

    The regex before the brackets matches an optional - and any leading 0s.

    The first part in the brackets (1?[0-9]{1,3}) matches 0-1999.

    The second part in the brackets (20[0-4][0-9]) matches 2000-2049.

    The third part in the brackets (205[0-5]) matches 2050-2055.

    0 讨论(0)
  • 2020-11-21 22:58

    So many answers, but noone reads (or cares) about the OPs side question in the comments?

    I'm writing an interpreter in OCaml .... how can i validate the input number within the range without using regex ?? – Trung Nguyen Mar 2 at 17:30

    As so many answers - correctly - pointed out that using regex is horrible for this scenario, lets think about other ways in OCaml! It is a while since I used OCaml, but with looking up a few constructs I was able to knock this together:

    let isInRange i = 
        not(i < -2055 or i > 2055);;
    
    let isIntAndInRange s = 
        try
        let i = int_of_string s in
        not(i < -2055 or i > 2055)
        with Failure "int_of_string" -> false;;
    
    let () = print_string "type a number: " in
    let s = read_line () in
    isIntAndInRange s
    

    If anything about is unclear, please read up on its syntax, type conversion functions and exception handling and input-output functions.

    The user input part is only used to demonstrate. It might be more convenient to use the read_int function there. But the basic concept of handling the exception stays the same.

    0 讨论(0)
  • 2020-11-21 22:59

    Try this:

    \-?\b0*(205[0-5]|20[0-4]\d|1?\d{3}|\d{1,2})\b
    
    0 讨论(0)
  • 2020-11-21 23:00

    Try with a very simple regex.

    ^([-0][0-1][0-9][0-9][0-9])$|^([-0]20[0-4][0-9])$|^([-0]205[0-5])$
    

    Visual representation

    enter image description here

    It's very simple to understand.

    • group 1 [-0][0-1][0-9][0-9][0-9] will cover [-1999, 1999] values
    • group 2 [-0]20[0-4][0-9] will cover [-2000,-2049] and [2000,2049] values
    • group 3 [-0]205[0-5] will cover [-2050, -2055] and [2050, 2055] values

    String.format("%05d", number) is doing very well done job here?

    Sample code: (Read inline comments for more clarity.)

    int[] numbers = new int[] { -10002, -3000, -2056, -2055, -2000, -1999, -20, 
                                -1,  0, 1, 260, 1999, 2000, 2046, 2055, 2056, 2955, 
                                 3000, 10002, 123456 };
    
    //valid range -2055 to 2055 inclusive
    
    Pattern p = Pattern.compile("^([-0][0-1][0-9][0-9][0-9])$|^([-0]20[0-4][0-9])$|^([-0]205[0-5])$");
    
    for (int number : numbers) {
        String string = String.format("%05d", number);
        Matcher m = p.matcher(string);
    
        if (m.find()) {
            System.out.println(number + " is in range.");
        } else {
            System.out.println(number + " is not in range.");
        }
    }
    

    output:

    -10002 is not in range.
    -3000 is not in range.
    -2056 is not in range.
    -2055 is in range.
    -2000 is in range.
    -1999 is in range.
    -20 is in range.
    -1 is in range.
    0 is in range.
    1 is in range.
    260 is in range.
    1999 is in range.
    2000 is in range.
    2046 is in range.
    2055 is in range.
    2056 is not in range.
    2955 is not in range.
    3000 is not in range.
    10002 is not in range.
    123456 is not in range.
    
    0 讨论(0)
  • 2020-11-21 23:01

    Using regular expressions to validate a numeric range

    To be clear: When a simple if statement will suffice

    if(num < -2055  ||  num > 2055)  {
       throw  new IllegalArgumentException("num (" + num + ") must be between -2055 and 2055");
    }
    

    using regular expressions for validating numeric ranges is not recommended.

    In addition, since regular expressions analyze strings, numbers must first be translated to a string before they can be tested. An exception is when the number happens to already be a string, such as when getting user input from the console.

    (To ensure the string is a number to begin with, you could use org.apache.commons.lang3.math.NumberUtils#isNumber(s))

    Despite this, figuring out how to validate number ranges with regular expressions is interesting and instructive.

    (The links in this answer come from the Stack Overflow Regular Expressions FAQ.)

    A one number range

    Rule: A number must be exactly 15.

    The simplest range there is. A regex to match this is

    \b15\b
    

    Word boundaries are necessary to avoid matching the 15 inside of 8215242.

    A two number range

    The rule: The number must be between 15 and 16. Here are three possible regexes:

    \b(15|16)\b
    \b1(5|6)\b
    \b1[5-6]\b
    

    (The groups are required for the "or"-ing, but they could be non-capturing: \b(?:15|16)\b)

    A number range "mirrored" around zero

    The rule: The number must be between -12 and 12.

    Here is a regex for 0 through 12, positive-only:

    \b(\d|1[0-2])\b
    

    Free-spaced:

    \b(         //The beginning of a word (or number), followed by either
       \d       //   Any digit 0 through 9
    |           //Or
       1[0-2]   //   A 1 followed by any digit between 0 and 2.
    )\b         //The end of a word
    

    Making this work for both negative and positive is as simple as adding an optional dash at the start:

    -?\b(\d|1[0-2])\b
    

    (This assumes no inappropriate characters precede the dash.)

    To forbid negative numbers, a negative lookbehind is necessary:

    (?<!-)\b(\d|1[0-2])\b
    

    Leaving the lookbehind out would cause the 11 in -11 to match. (The first example in this post should have this added.)

    Note: \d versus [0-9]

    In order to be compatible with all regex flavors, all \d-s should be changed to [0-9]. For example, .NET considers non ASCII numbers, such as those in different languages, as legal values for \d. Except for in the last example, for brevity, it's left as \d.

    (With thanks to @TimPietzcker)

    Three digits, with all but the first digit equal to zero

    Rule: Must be between 0 and 400.

    A possible regex:

    (?<!-)\b([1-3]?\d{1,2}|400)\b
    

    Free spaced:

       (?<!-)          //Something not preceded by a dash
       \b(             //Word-start, followed by either
          [1-3]?       //   No digit, or the digit 1, 2, or 3
             \d{1,2}   //   Followed by one or two digits (between 0 and 9)
       |               //Or
          400          //   The number 400
       )\b             //Word-end
    

    Another possibility that should never be used:

    \b(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125|126|127|128|129|130|131|132|133|134|135|136|137|138|139|140|141|142|143|144|145|146|147|148|149|150|151|152|153|154|155|156|157|158|159|160|161|162|163|164|165|166|167|168|169|170|171|172|173|174|175|176|177|178|179|180|181|182|183|184|185|186|187|188|189|190|191|192|193|194|195|196|197|198|199|200|201|202|203|204|205|206|207|208|209|210|211|212|213|214|215|216|217|218|219|220|221|222|223|224|225|226|227|228|229|230|231|232|233|234|235|236|237|238|239|240|241|242|243|244|245|246|247|248|249|250|251|252|253|254|255|256|257|258|259|260|261|262|263|264|265|266|267|268|269|270|271|272|273|274|275|276|277|278|279|280|281|282|283|284|285|286|287|288|289|290|291|292|293|294|295|296|297|298|299|300|301|302|303|304|305|306|307|308|309|310|311|312|313|314|315|316|317|318|319|320|321|322|323|324|325|326|327|328|329|330|331|332|333|334|335|336|337|338|339|340|341|342|343|344|345|346|347|348|349|350|351|352|353|354|355|356|357|358|359|360|361|362|363|364|365|366|367|368|369|370|371|372|373|374|375|376|377|378|379|380|381|382|383|384|385|386|387|388|389|390|391|392|393|394|395|396|397|398|399|400)\b
    

    Final example: Four digits, mirrored around zero, that does not end with zeros.

    Rule: Must be between -2055 and 2055

    This is from a question on stackoverflow.

    Regex:

    (-?\b(?:20(?:5[0-5]|[0-4][0-9])|1[0-9]{3}|[1-9][0-9]{0,2}|(?<!-)0+))\b
    

    Regular expression visualization

    Debuggex Demo

    Free-spaced:

    (             //Capture group for the entire number
       -?\b             //Optional dash, followed by a word (number) boundary
       (?:20            //Followed by "20", which is followed by one of 
             (?:5[0-5]        //50 through 55
               |                  //or
             [0-4][0-9])      //00 through 49
          |                                         //or
             1[0-9]{3}        //a one followed by any three digits
          |                                         //or
             [1-9][0-9]{0,2}  //1-9 followed by 0 through 2 of any digit
          |                                         //or
             (?<!-)0+         //one-or-more zeros *not* preceded by a dash
       )                 //end "or" non-capture group
    )\b            //End number capture group, followed by a word-bound
    

    (With thanks to PlasmaPower and Casimir et Hippolyte for the debugging assistance.)

    Final note

    Depending on what you are capturing, it is likely that all sub-groups should be made into non-capture groups. For example, this:

    (-?\b(?:20(?:5[0-5]|[0-4][0-9])|1?[0-9]{1,3})\b)
    

    Instead of this:

    -?\b(20(5[0-5]|[0-4][0-9])|1?[0-9]{1,3})\b
    

    Example Java implementation

      import  java.util.Scanner;
      import  java.util.regex.Matcher;
      import  java.util.regex.Pattern;
      import  org.apache.commons.lang.math.NumberUtils;
    /**
      <P>Confirm a user-input number is a valid number by reading a string an testing it is numeric before converting it to an it--this loops until a valid number is provided.</P>
    
      <P>{@code java UserInputNumInRangeWRegex}</P>
     **/
    public class UserInputNumInRangeWRegex  {
      public static final void main(String[] ignored)  {
    
         int num = -1;
         boolean isNum = false;
    
         int iRangeMax = 2055;
    
         //"": Dummy string, to reuse matcher
         Matcher mtchrNumNegThrPos = Pattern.compile("(-?\\b(?:20(?:5[0-5]|[0-4][0-9])|1[0-9]{3}|[1-9][0-9]{0,2}|(?<!-)0+))\\b").matcher("");
    
         do  {
            System.out.print("Enter a number between -" + iRangeMax + " and " + iRangeMax + ": ");
            String strInput = (new Scanner(System.in)).next();
            if(!NumberUtils.isNumber(strInput))  {
               System.out.println("Not a number. Try again.");
            }  else if(!mtchrNumNegThrPos.reset(strInput).matches())  {
               System.out.println("Not in range. Try again.");
            }  else  {
               //Safe to convert
               num = Integer.parseInt(strInput);
               isNum = true;
            }
         }  while(!isNum);
    
         System.out.println("Number: " + num);
      }
    

    }

    Output

    [C:\java_code\]java UserInputNumInRangeWRegex
    Enter a number between -2055 and 2055: tuhet
    Not a number. Try again.
    Enter a number between -2055 and 2055: 283837483
    Not in range. Try again.
    Enter a number between -2055 and 2055: -200000
    Not in range. Try again.
    Enter a number between -2055 and 2055: -300
    Number: -300
    

    Original answer to this stackoverflow question

    This is a serious answer that fits your specifications. It is similar to @PlasmaPower's answer.

    (-?\b(?:20(?:5[0-5]|[0-4][0-9])|1[0-9]{3}|[1-9][0-9]{0,2}|(?<!-)0+))\b
    

    Regular expression visualization

    Debuggex Demo

    0 讨论(0)
提交回复
热议问题