É fácil descrever uma máquina de estados finitos que reconhece múltiplos de 9: acompanhe a soma dos dígitos (mod 9) e adicione o dígito que for aceito em seguida. Esse FSM tem apenas 9 estados, muito simples! Pela equivalência entre reconhecimento de FSM e linguagens regulares, há uma expressão regular para múltiplos de 9. No entanto, qualquer expressão regular é provável ... muito ... longa. Provavelmente da ordem de um gigabyte.
Há um exemplo elaborado em https://www.quaxio.com/triple/ para múltiplos de 3. Na parte inferior da página, o autor fornece uma solução um pouco "otimizada pela mão", um pouco menor que a ingênua conversão de FSM para regex.
O desafio:
Você deve criar um regex para detectar múltiplos de 9. Como é esperado que esse regex seja muito longo, solicito que você forneça um programa que possa imprimir seu regex. (Se você realmente deseja fornecer uma regex inteira, talvez a hospede em outro lugar e faça a ligação aqui!)
Você deve poder nos dizer a contagem exata de caracteres da saída do seu programa - portanto, ter um programa que simplesmente tente todas as expressões regulares até um certo comprimento, até encontrar um que funcione, não é aceitável, a menos que seja executado com a rapidez necessária. execute-o até a conclusão e forneça o comprimento de regex resultante!
Os pontos são para ter o menor regex de saída, não com base no tamanho do programa, é claro. Como o regex é o "programa" que estou solicitando, e é muito longo para transmitir convenientemente aqui, ainda estou identificando esse código-golfe.
Regras:
- A entrada incluirá apenas caracteres correspondentes
[0-9]*
. - Sua regex deve corresponder a múltiplos de 9, mas nada mais. Casos que não são inteiramente compostos dos dígitos de 0 a 9 e são entradas inválidas podem corresponder ou falhar conforme desejado.
- Dada a motivação que é facilmente reconhecida por um DFA, o regex resultante deve realmente ser expressão regular na terminologia mais teórica, ou seja, apenas operadores sob os quais os idiomas regulares são fechados. Para ser preciso, as únicas coisas que são permitidas:
- Literais, intervalos de caracteres (
[ab]
,[a-f]
,[^k]
), Fecho de Kleene (*
), âncoras (^
e$
), agrupando via parênteses, alternância (|
), termos opcionais (?
), um-ou-mais termos (+
), lookaheads ((?=)
), lookaheads negativos ((?!)
), lookbehinds ((?<=)
), lookbehinds negativos ((?<!)
), condicionais (como em https://www.regular-expressions.info/conditional.html -(?(?=test)then|else)
) e referências anteriores de comprimento limitado (veja abaixo).
- Literais, intervalos de caracteres (
- Exemplos de coisas que não são permitidas:
- Referências anteriores de comprimento arbitrário, referências futuras, recursão, sub-rotinas, construções em loop, código executável, qualquer variação de 'eval' ou construções internas para converter a string em um valor aritmético.
- As referências anteriores que podem ser mostradas como tendo uma cadeia de ligação de comprimento limitado são aceitáveis, pois podem ser armazenadas em estado finito e não alteram a regularidade do idioma. Por exemplo, o regex
(..2.[3-5])4\1.\1
é aceitável, pois há um comprimento vinculado no grupo de captura\1
. Esta é uma construção regular. Uma construção como(2*)0\1
não é aceitável, pois o grupo capturado não pode ser armazenado em estado finito. - Sua regex é livre para aceitar ou rejeitar números inteiros com zeros iniciais estranhos, conforme desejar. No entanto, a sequência
"0"
deve ser aceita.
^(0|9|(?<c>1|(?<c>2|(?<c>3|(?<c>4|(?<c>5|(?<c>6|(?<c>7|(?<c>8))))))))((?<-c>){9})?)*$(?(c).)