Регулярное выражение для кратных 9

14

Легко описать конечный автомат, который распознает кратные 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"должна быть принята.
Алекс Мейбург
источник
2
Связанный , не уверен, что это будет считаться дубликатом
только ASCII
Ах, хм! У меня был поиск "регулярное выражение множественное", но не "регулярное выражение делится". Полагаю, это очень похоже, да.
Алекс Мейбург
11
Пока не сказано, так что добро пожаловать в PPCG и интересный первый вызов! Как упомянул другой пользователь, часто рекомендуется, но не обязательно, публиковать предложения о вызовах в Песочнице, чтобы они могли получить обратную связь, прежде чем публиковать на главной. Однако это хорошо продуманная и понятная задача, поэтому нет причин переносить ее в Песочницу. Надеюсь, вам понравится наше сообщество!
День рождения Кэрда
Возможны решения менее чем 200 кибибайтов, так что это не будет ТАКИМ огромным
Тон Хоспел
3
Решение с использованием расширений .NET:^(0|9|(?<c>1|(?<c>2|(?<c>3|(?<c>4|(?<c>5|(?<c>6|(?<c>7|(?<c>8))))))))((?<-c>){9})?)*$(?(c).)
Нил

Ответы:

3

Haskell , 207 535 202 073 байта

5,462 байта, сэкономленные при использовании 0|9вместо, [09]где это возможно.

digits n
  | x == 0    = "0|9"
  | otherwise = show x
  where x = mod n 9

regex 0 = "[09]*"
regex n = (regex' n (-1) (-1)) ++ "*"

regex' 0 start end = digits (end - start)
regex' n start end = '(':(regex' 0 start end) ++ (concat ['|':(regex' (n-x) (start-x) (-1)) ++ (regex (n-x))
                                                  ++ (regex' (n-x) (-1) (end-x)) | x <- [1..n]]) ++ ")"

main = do
  putStr ("^" ++ (regex 8) ++ "$")

Попробуйте онлайн!

Просто быстрая адаптация регулярного выражения, приведенного в сносках связанной статьи, для начала работы.

Pastebin выходного регулярного выражения , предоставлено Германом Лауэнштейном.

Хотя я не смог протестировать полное регулярное выражение, модификация программы для проверки делимости на 3 вместо этого дает нечто точно эквивалентное регулярному выражению, на котором я это основывал. Кроме того, изменение программы для проверки делимости суммы цифр на 4 или 5 также, похоже, работает с числами, на которых я ее проверял.

Nitrodon
источник
Вы также можете проверить, что ваш метод дает делимость на 2 (должно быть что-то вроде /even$/) и делимость на 5 (должно быть что-то вроде /[05]$/). PS: упомяните язык вашего кода
Тон Хоспел
Вот пастбина с выводом (все случаи ([09]|заменены на, (0|9|чтобы сохранить тысячи байтов)
Герман Л