Regular Expression for any number divisible by 60 using C# .Net?

前端 未结 6 1399
梦谈多话
梦谈多话 2021-01-18 10:32

I need to apply validation on input time intervals that are taken in as seconds. Now i am not really good at Regular expressions. So can any body help making a regular expre

相关标签:
6条回答
  • 2021-01-18 10:44

    I've come up with this:

    ^((?=[^147]*(([147][^147]*){3})*$)(?=[^258]*(([258][^258]*){3})*$)|(?=[^147]*(([147][^147]*){3})*[147][^147]*$)(?=[^258]*(([258][^258]*){3})*[258][^258]*$)|(?=[^147]*(([147][^147]*){3})*([147][^147]*){2}$)(?=[^258]*(([258][^258]*){3})*([258][^258]*){2}$))\d*0(?<=[02468][048]|[13579][26]|^0)$

    Note: I didn't use non-capturing groups for the sake of simplicity.

    Edit: Shorter version:

    ^(?=[^147]*(?:(?:[147][^147]*){3})*(?:()|([147][^147]*)|((?:[147][^147]*){2}))$)(?=[^258]*(?:(?:[258][^258]*){3})*(?:()|([258][^258]*)|((?:[258][^258]*){2}))$)((?(1)(?(4)|.$)|.$)|(?(2)(?(5)|.$)|.$)|(?(3)(?(6)|.$)|.$))\w*0(?<=[02468]0|^0)$

    0 讨论(0)
  • 2021-01-18 10:49

    (+,/,-,*) in Regex are not used as mathematical operators. Use JavaScript instead.

    0 讨论(0)
  • 2021-01-18 10:53

    Why not do N % 60 ?

    Why you want to use regex for a job which can easily be done using one operator ?

    0 讨论(0)
  • 2021-01-18 10:53

    As others have mentioned, regular expressions are completely the wrong tool to use for this. Rather, use TryParse to convert the string to an integer, and then test whether the integer is divisible by 60.

    That said, it is instructive to see how this could possibly work with a regexp.

    First off, of the one-digit numbers, only 0 is evenly divisible by 60. Of the non-one-digit numbers, all numbers divisible by 60 are also divisible by 20, and therefore end in 00, 20, 40, 60 or 80. That is easily tested with a regexp.

    Suppose it passes the first test. We know from this test that the number is divisible by 20. Now all we need to do is show that it is divisible by 3. If it is, then it is divisible by both 20 and 3 and therefore must be divisible by 60, since 20 and 3 are coprime.

    So we need a regular expression that can determine if a number is divisible by 3.

    It is well known that numbers divisible by three are such that the sum of their digits is divisible by 3.

    It is also well known that every regular expression corresponds to a finite state machine, and every finite state machine corresponds to a regular expression.

    Therefore if we can come up with a finite state machine that determines divisibility by three, we're done.

    This is easily done. Our finite state machine has three states, A, B and C. The start state is A. The accepting state is A. The transitions are:

    When in state A, inputs 0, 3, 6 and 9 go to state A. Inputs 1, 4 and 7 go to state B. Inputs 2, 5 and 8 go to state C.

    When in state B, inputs 0, 3, 6 and 9 go to state B. Inputs 1, 4 and 7 go to state C. Inputs 2, 5 and 8 go to state A.

    When in state C, inputs 0, 3, 6 and 9 go to state C. Inputs 1, 4 and 7 go to state A. Inputs 2, 5 and 8 go to state B.

    All other inputs go to an error state.

    And we're done; we have a finite state machine that checks for divisibility by 3. Therefore we can build a regexp that checks for divisibility by 3; if we combine that with the regexp that checks for divisibility by 20, then we have the desired regular expression. The language of numbers written in decimal notation divisible by 60 is a regular language.

    The actual construction of such a regular expression is left as an exercise. (Looks like that's what tiftik has done.)

    Exercise: can you come up with a regular expression that determines if string contains a decimal number that is evenly divisible by 70? If you can, let's see it. If not, can you provide a proof that no such regular expression exists? (That is, that the language I am describing is not regular.)

    0 讨论(0)
  • 2021-01-18 11:01

    Regular expressions are the wrong tool for this job. Instead, try dividing by 60 and see if there is no remainder:

    if (value % 60 == 0) {
      // is divisible by 60
      // ... do something ...
    }
    
    0 讨论(0)
  • 2021-01-18 11:05

    Note: Regular expressions are not the right tool for this. This is just for fun and to see how it could be done.

    Here is a regular expression that tests if a number is divisible by 60:

    ^0$|^(?!0)(?=.*[02468]0$)(?:[0369]|[147](?:[0369]*[147][0369]*[258])*(?:[0369]*[258]|[0369]*[147][0369]*[147])|[258](?:[0369]*[258][0369]*[147])*(?:[0369]*[147]|[0369]*[258][0369]*[258]))*0$

    It works by testing if the number is divisible by 3 and using a lookahead to check if it is divisble by 20. It differs from the regular expression posted by tiftik in the following ways:

    • It is slightly shorter.
    • It uses non-capturing groups.
    • Many languages (for example Javascript )don't support variable length lookbehind assertions. This regular expression does not use lookbehinds so it can for example also be used for client-side validation in a web application.
    • It disallows numbers with leading zeros (if you want to allow leading zeros just remove the (?!0)).

    This is the code I used to generate and test it:

    using System;
    using System.Text;
    using System.Text.RegularExpressions;
    
    class Program
    {
        Regex createRegex()
        {
            string a = "[0369]*";
            string b = "a[147]";
            string c = "a[258]";
            string r = "^0$|^(?!0)(?=.*[02468]0$)(?:[0369]|[147](?:bc)*(?:c|bb)|[258](?:cb)*(?:b|cc))*0$";
            r = r.Replace("b", b).Replace("c", c).Replace("a", a);
            return new Regex(r);
        }
    
        bool isDivisibleBy3(string s)
        {
            int sumOfDigits = 0;
            foreach (char c in s)
            {
                sumOfDigits += c - '0';
            }
            return sumOfDigits % 3 == 0;
        }
    
        bool isDivisibleBy20(string s)
        {
            return Regex.IsMatch(s, "^0$|[02468]0$");
        }
    
        bool isDivisibleBy60(string s)
        {
            return isDivisibleBy3(s) && isDivisibleBy20(s);
        }
    
        bool isValid(string s)
        {
            return Regex.IsMatch(s, "^0$|^[1-9][0-9]*$");
        }
    
        void Run()
        {
            Regex regex = createRegex();
            Console.WriteLine(regex);
    
            // Test on some random strings.
            Random random = new Random();
            for (int i = 0; i < 100000; ++i)
            {
                int length = random.Next(50);
                StringBuilder sb = new StringBuilder();
                for (int j = 0; j < length; ++j)
                {
                    sb.Append(random.Next(10));
                }
                string s = sb.ToString();
                bool isMatch = regex.IsMatch(s);
                bool expected = isValid(s) && isDivisibleBy60(s);
                if (isMatch != expected)
                {
                    Console.WriteLine("Failed for " + s);
                }
            }
        }
    
        static void Main()
        {
            new Program().Run();
        }
    }
    
    0 讨论(0)
提交回复
热议问题