Regex Pattern number1 to number2

前端 未结 3 1343
耶瑟儿~
耶瑟儿~ 2021-01-21 22:37

I\'m searching for a pattern for the following behavior:

number1-number2
number1: Can be everything >= 0 and <= int.MaxValue
number2: Can be everything >         


        
3条回答
  •  鱼传尺愫
    2021-01-21 23:13

    Solution

    It is possible to test it using regex - but you should prefer a solution in code because it will be much faster. This regex needs a lot of backtracking. The only advantage of this regex is that it works for an arbitrary number length.

    (?:^0+-\d+$)
    |
    (?:^(?>0*)(?\d+)-(?>0*)\k$)
    |
    (?:
        (?:^(?>0*)(?\d)+-(?>0*)(?<-length>\d)*(?(length)(?!))\d+$)
        |
        (
            (?=^(?>0*)(?\d)+-(?>0*)(?<-o>\d)*(?(o)(?!))$)
            ^
                (?>0*)
                (?\d*)
                (?:(?0)|(?1)|(?2)|(?3)|(?4)|(?5)|(?6)|(?7)|(?8)|(?9))
                \d*
            -
                (?>0*)
                \k
                (?(g0)[1-9]|(?(g1)[2-9]|(?(g2)[3-9]|(?(g3)[4-9]|(?(g4)[5-9]|(?(g5)[6-9]|(?(g6)[7-9]|(?(g7)[89]|(?(g8)9|(?!))))))))))
                \d*
            $
        )
    )
    

    This matches for every x-y where x <= y for positive integer numbers including leeding zeros.

    DEMO

    It doesn't work for chars.

    Explanation

    I was able to create a regex that matches x-y for all x < y. The question was x <= y. So I splitted the question to x = y | x < y.

    We need to handle that the first or both numbers does only contain zeros but that's trivial:

    ^0+-\d+$
    

    Now the case x = y

    ^(?>0*)(?\d+)-(?>0*)\k$
    

    The tricky part is x < y.

    1. x is smaller than y if x is shorter in char length than y (leeding zeros are captured by an atomic group):

      ^(?>0*)(?\d)+-(?>0*)(?<-length>\d)*(?(length)(?!))\d+

      This first group captures the whole number by one capture per digit. After the separator a balancing group definition clears the capture stack and forces at least one more digit.

    2. Both numbers are of the same length (if the first number is longer it is also greater and should not match).

      To ensure that both numbers are of the same length I started with a positive look behind assertion that ensures it the same way I tested for a longer number in step 1:

      (?=^(?>0*)(?\d)+-(?>0*)(?<-o>\d)*(?(o)(?!))$)

      After that the algorithm is simple. Start at the beginning. If the current digit is equal go to the next digit. If the current x-digit is slower than the current y-digit we're finished and a match is found. If it's slower we should not match. This is done by that pattern:

      ^
          (?>0*)   # cut out leeding zeros
          (?\d*)
          .*
      -
          (?>0*)   # cut out leeding zeros
          \k  # both numbers start with the same part
          .*
      $
      

      And now the check for one digit. There are only 10 possibilities [0-9]. Each of them is captures by a single group:

      (?0)|(?1)|(?2)|(?3)|(?4)|(?5)|(?6)|(?7)|(?8)|(?9)

      Now we're able to use conditions to check whether the current y-digit is greater then the current x-digit. Lets show for 0 and 1:

      (?0)|(?1): If a 0 matches for the current x-digit there are only [1-9] for the current y-digit. If 1 matches only [2-9] is able. This could be used in a condition:

      (?(g0)[1-9]|...) what means if g0 has a capture [1-9] has to match otherwise the rest has to match. This is combined to:

      (?(g0)[1-9]|(?(g1)[2-9]|(?(g2)[3-9]|(?(g3)[4-9]|(?(g4)[5-9]|(?(g5)[6-9]|(?(g6)[7-9]|(?(g7)[89]|(?(g8)9|(?!))))))))))

      The last trick is that none of the groups g[0-8] has been matched only g9 is available and there is no greater digit possible and the match should fail (?!).

    This all has been combined to the whole regex that matches x-y for all x <= y.

提交回复
热议问题