Regex para múltiplos de 9


14

É 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).
  • 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\1nã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.

2
Relacionado , não tenho certeza se isso seria considerado uma duplicação
somente ASCII

Ah, hmm! Eu pesquisei "regex multiple", mas não "regex divisible". Suponho que seja muito parecido, sim.
Alex Meiburg

11
Ainda não foi dito, então seja bem-vindo ao PPCG e ao interessante primeiro desafio! Conforme mencionado por outro usuário, geralmente é recomendável, mas não obrigatório, postar propostas de desafio no Sandbox para que eles possam receber feedback antes de postar no site principal. No entanto, esse é um desafio bem pensado e claro, portanto não há razão para movê-lo para o Sandbox. Espero que você goste da nossa comunidade!
caird coinheringaahing

Soluções de menos de 200 kibibytes são possíveis, por isso não será TÃO
GRANDE

3
Solução usando as extensões do .NET:^(0|9|(?<c>1|(?<c>2|(?<c>3|(?<c>4|(?<c>5|(?<c>6|(?<c>7|(?<c>8))))))))((?<-c>){9})?)*$(?(c).)
Neil

Respostas:


3

Haskell , 207.535 202.073 bytes

5.462 bytes salvos usando em 0|9vez de sempre [09]que possível.

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) ++ "$")

Experimente online!

Apenas uma rápida adaptação da expressão regular apresentada nas notas de rodapé do artigo vinculado para começar.

Pasta do regex de saída , cortesia de Herman Lauenstein.

Embora eu não tenha sido capaz de testar a regex completa, a modificação do programa para verificar a divisibilidade por 3 fornece algo exatamente equivalente à regex em que baseei isso. Além disso, modificar o programa para verificar a divisibilidade da soma dos dígitos em 4 ou 5 também parece funcionar nos números em que o testei.


Você também pode testar o que seu método fornece para a divisibilidade por 2 (deve ser algo como /even$/) e divisibilidade por 5 (deve ser algo como /[05]$/). PS: Mencione o idioma do seu código
Ton Hospel

Aqui está um pastebin com a saída (com todas as ocorrências de ([09]|substituídas por (0|9|para salvar milhares de bytes) #
238 Herman L
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.