Легко описать конечный автомат, который распознает кратные 9: отслеживайте сумму цифр (мод 9) и добавьте любую цифру, которая будет принята следующей. У такого автомата всего 9 состояний, очень просто! В силу эквивалентности между распознаваемостью FSM и регулярными языками существует регулярное выражение для кратных 9. Однако любое такое регулярное выражение, вероятно, ... очень ... длинное. Как в, вероятно, порядка гигабайта.
На https://www.quaxio.com/triple/ приведен работающий пример, кратный 3. В нижней части страницы автор предлагает несколько «оптимизированное вручную» решение, которое немного короче, чем наивное преобразование из FSM для регулярного выражения.
Соревнование:
Вы должны сделать регулярное выражение, чтобы обнаружить кратные числа 9. Поскольку ожидается, что такое регулярное выражение будет очень длинным, я прошу вас предоставить программу, которая может распечатать ваше регулярное выражение. (Если вы действительно хотите дать целое регулярное выражение, возможно, разместите его в другом месте и свяжите здесь!)
Вы должны быть в состоянии сообщить нам точное количество символов в выходных данных вашей программы - поэтому наличие программы, которая просто пробует все регулярные выражения до определенной длины, пока не найдет ту, которая работает, недопустимо, если она не выполняется достаточно быстро, чтобы вы могли запустите его до конца и дайте нам длину регулярного выражения!
Точки за то, что они имеют самое короткое регулярное выражение, не зависящее от длины программы, конечно. Поскольку регулярное выражение - это «программа», о которой я прошу, и она слишком длинна для удобной передачи здесь, я все еще отмечаю этот код-гольф.
Правила:
- На входе будут только совпадения символов
[0-9]*
. - Ваше регулярное выражение должно соответствовать кратному 9, но не больше. Случаи, которые не состоят полностью из цифр 0-9 и являются недопустимыми вводами, могут совпадать или не соответствовать, как вы пожелаете.
- Учитывая мотивацию, что DFA легко его распознает, полученное регулярное выражение должно фактически быть регулярным выражением в более теоретической терминологии, то есть только операторами, в которых регулярные языки закрыты. Если быть точным, то разрешено только одно:
- Литералов диапазоны символов (
[ab]
,[a-f]
,[^k]
), клиниевская звезда (*
), якорь (^
и$
), группировка с помощью скобок, чередования (|
), необязательные термины (?
), одно- или-более терминов (+
), lookaheads ((?=)
), отрицательных lookaheads ((?!)
), lookbehinds ((?<=)
), отрицательный lookbehinds ((?<!)
), условные выражения ( как в https://www.regular-expressions.info/conditional.html -(?(?=test)then|else)
) и обратные ссылки ограниченной длины (см. ниже).
- Литералов диапазоны символов (
- Примеры вещей, которые не допускаются:
- Обратные ссылки произвольной длины, прямые ссылки, рекурсия, подпрограммы, циклические конструкции, исполняемый код, любой вариант 'eval' или встроенные конструкции для приведения строки к арифметическому значению.
- Обратные ссылки, для которых может быть показана строка привязки ограниченной длины, являются приемлемыми, поскольку они могут храниться в конечном состоянии и не изменяют регулярность языка. Например, регулярное выражение
(..2.[3-5])4\1.\1
является приемлемым, так как для группы захвата существует ограниченная длина\1
. Это обычная конструкция. Такая конструкция, как(2*)0\1
неприемлемая, поскольку захваченная группа не может быть сохранена в конечном состоянии. - Ваше регулярное выражение свободно принимать или отклонять целые числа с лишними начальными нулями, как вы пожелаете. Тем не менее, строка
"0"
должна быть принята.
^(0|9|(?<c>1|(?<c>2|(?<c>3|(?<c>4|(?<c>5|(?<c>6|(?<c>7|(?<c>8))))))))((?<-c>){9})?)*$(?(c).)