Регулярное выражение для любого числа, делимого на 60 с помощью C#.Net?

Мне нужно применить проверку на входных временных интервалах, которые принимаются в секундах. Теперь я не очень хорош в регулярных выражениях. Так может любой орган, помогите сделать регулярное выражение, которое может проверить, делится ли число на 60.

Мне было интересно, могу ли я использовать, чтобы проверить, что число делится на 10, а затем проверить, делится ли то же самое на 6.

для числа, кратного 10, здесь [d * 0] - это выражение, которое я предполагаю. Пожалуйста, исправьте я, если ошибаюсь.

надеюсь, кто-то решит мою проблему.

спасибо

6 ответов


(+,/,-,*) в Regex не используются в качестве математических операторов. Вместо этого используйте JavaScript.


почему бы не сделать N % 60 ?

почему вы хотите использовать регулярное выражение для задания, которое можно легко выполнить с помощью одного оператора ?


Как упоминали другие, регулярными выражениями являются совершенно неправильный инструмент использовать для этого. Вместо этого используйте TryParse для преобразования строки в целое число, а затем проверьте, делится ли целое число на 60.

тем не менее, поучительно посмотреть, как это может работать с регулярным выражением.

во-первых, из однозначных чисел только 0 равномерно делится на 60. Из не-одноразрядных чисел все числа, делимые на 60, также делятся на 20, и, следовательно, конец в 00, 20, 40, 60 или 80. Это легко протестировать с помощью regexp.

предположим, что он проходит первый тест. Из этого теста мы знаем, что число делится на 20. Теперь все, что нам нужно сделать, это показать, что оно делится на 3. Если это так, то оно делится на 20 и 3 и, следовательно, должно быть делимо на 60, так как 20 и 3 являются соучастием.

поэтому нам нужно регулярное выражение, которое может определить, делится ли число на 3.

Это хорошо известно, что числа, делящиеся на три таковы, что сумма их цифр делится на 3.

также хорошо известно, что каждое регулярное выражение соответствует конечной машине, а каждая конечная машина соответствует регулярному выражению.

поэтому, если мы можем придумать машину с конечным состоянием, которая определяет делимость на три, мы закончили.

Это легко сделать. Наша конечная машина имеет три состояния: A, B и C. начальное состояние-A. принимающее состояние-A. переходы:

когда в состоянии A входы 0, 3, 6 и 9 переходят в состояние A. входы 1, 4 и 7 переходят в состояние B. входы 2, 5 и 8 переходят в состояние C.

когда в состоянии B входы 0, 3, 6 и 9 переходят в состояние B. входы 1, 4 и 7 переходят в состояние C. входы 2, 5 и 8 переходят в состояние A.

когда в состоянии C входы 0, 3, 6 и 9 переходят в состояние C. входы 1, 4 и 7 переходят в состояние A. входы 2, 5 и 8 переходят в состояние B.

все другие входные данные переходят в состояние ошибки.

и мы закончили, у нас есть конечный автомат, который проверяет делимость на 3. Поэтому мы можем построить регулярное выражение, которое проверяет делимость на 3; Если мы объединим это с регулярным выражением, которое проверяет делимость на 20, то у нас есть желаемое регулярное выражение. язык чисел, записанных в десятичной системе счисления делится на 60 является регулярным языком.

фактическая конструкция такого регулярного выражения ушел как упражнение. (Похоже, что tiftik сделал.)

упражнение: можете ли вы придумать регулярное выражение, которое определяет, содержит ли строка десятичное число, которое равномерно делится на 70? Если можешь, давай посмотрим. Если нет, можете ли вы предоставить доказательство того, что такого регулярного выражения не существует? (То есть язык, который я описываю, не является регулярным.)


Я придумал это:

^((?=[^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)$

примечание: Я не использовал группы без захвата для простоты.

Edit: более короткая версия:

^(?=[^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)$


Примечание: регулярные выражения не являются правильным инструментом для этого. Это просто для удовольствия и посмотреть, как это можно сделать.

вот регулярное выражение, которое проверяет, делится ли число на 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$

он работает, проверяя, делится ли число на 3 и используя lookahead, чтобы проверить, делится ли оно на 20. Он отличается от регулярное выражение опубликовано tiftik следующим образом:

  • это немного короче.
  • он использует группы без захвата.
  • многие языки (например, Javascript )не поддерживают утверждения lookbehind переменной длины. Это регулярное выражение не использует lookbehinds, поэтому его можно также использовать для проверки на стороне клиента в веб-приложении.
  • он запрещает числа с ведущими нулями (если вы хотите разрешить ведущие нули просто удалить (?!0)).

Это код, который я использовал для генерации и проверьте это:

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();
    }
}

регулярные выражения являются неправильным инструментом для этого задания. Вместо этого попробуйте разделить на 60 и посмотреть, нет ли остатка:

if (value % 60 == 0) {
  // is divisible by 60
  // ... do something ...
}