Regex per multipli di 9


14

È facile descrivere una macchina a stati finiti che riconosce multipli di 9: tenere traccia della somma delle cifre (mod 9) e aggiungere qualunque cifra venga accettata successivamente. Tale FSM ha solo 9 stati, molto semplici! Dall'equivalenza tra riconoscibilità degli FSM e linguaggi regolari, esiste un'espressione regolare per multipli di 9. Tuttavia, ogni espressione regolare di questo tipo è probabilmente ... molto ... lunga. Come in, probabilmente nell'ordine di un gigabyte.

C'è un esempio funzionante su https://www.quaxio.com/triple/ per multipli di 3. Nella parte inferiore della pagina, l'autore fornisce una soluzione un po '"ottimizzata a mano" che è un po' più corta della conversione ingenua da FSM per regex.

La sfida:

È necessario creare una regex per rilevare multipli di 9. Poiché una regex dovrebbe essere molto lunga, ti chiedo di fornire un programma in grado di stampare la tua regex. (Se vuoi davvero dare un'intera regex, magari ospitala altrove e collegala qui!)

Devi essere in grado di dirci il conteggio esatto dei caratteri dell'output del tuo programma - quindi avere un programma che prova semplicemente tutte le regex fino a una certa lunghezza, fino a quando non trova uno che funziona, non è accettabile a meno che non sia abbastanza veloce da poter eseguilo fino al completamento e dacci la lunghezza regex risultante!

I punti sono per avere il regex di output più breve, ovviamente non basato sulla lunghezza del programma. Dato che il regex è il "programma" che sto chiedendo, ed è troppo lungo per trasmetterlo comodamente qui, sto ancora taggando questo codice-golf.

Regole:

  • L'input includerà solo la corrispondenza dei caratteri [0-9]*.
  • La tua regex dovrebbe corrispondere a multipli di 9, ma non a nient'altro. I casi che non sono composti interamente dalle cifre 0-9 e che sono input non validi possono corrispondere o fallire come desideri.
  • Data la motivazione che è facilmente riconoscibile da un DFA, la regex risultante deve in realtà essere espressione regolare nella terminologia più teorica, cioè solo operatori in cui le lingue regolari sono chiuse. Per essere precisi, le uniche cose che sono consentite:
    • Letterali, intervalli di caratteri ( [ab], [a-f], [^k]), Kleene stella ( *), ancore ( ^e $), il raggruppamento tramite parentesi, alternanza ( |), termini facoltativi ( ?), uno-o-più termini ( +), lookaheads ( (?=)), lookaheads negativi ( (?!)), lookbehinds ( (?<=)), lookbehinds negativo ( (?<!)), condizionali (come in https://www.regular-expressions.info/conditional.html - (?(?=test)then|else)) e backreferenze di lunghezza limitata (vedi sotto).
  • Esempi di cose che non sono consentite:
    • Backreferenze di lunghezza arbitraria, riferimenti in avanti, ricorsione, subroutine, costrutti loop, codice eseguibile, qualsiasi variazione di 'eval' o costrutti incorporati per lanciare la stringa su un valore aritmetico.
  • Sono accettabili le backreferenze che possono mostrare una stringa di rilegatura di lunghezza limitata, in quanto possono essere archiviate allo stato finito e non alterano la regolarità della lingua. Ad esempio, la regex (..2.[3-5])4\1.\1è accettabile, in quanto esiste una lunghezza legata sul gruppo di acquisizione \1. Questa è una costruzione regolare. Un costrutto come (2*)0\1non è accettabile, in quanto il gruppo acquisito non può essere archiviato in stato finito.
  • Il tuo regex è libero di accettare o rifiutare numeri interi con zero iniziali estranei come desideri. Tuttavia, la stringa "0"deve essere accettata.

2
Correlati , non sono sicuro se questo sarebbe considerato un duplicato
solo ASCII il

Ah! Ho cercato "regex multiple" ma non "regex divisible". Suppongo che sia terribilmente simile, sì.
Alex Meiburg,

11
Non è ancora stato detto, quindi benvenuti in PPCG e interessante prima sfida! Come accennato da un altro utente, è spesso consigliato, ma non necessario, pubblicare proposte di sfida nella Sandbox in modo che possano ricevere feedback, prima di pubblicare sulla main. Tuttavia, questa è una sfida ben ponderata e chiara, quindi non c'è motivo di trasferirla nella Sandbox. Spero ti piaccia la nostra community!
caird coinheringaahing il

Sono possibili soluzioni con meno di 200 kibibyte, quindi non sarà così grande
Ton Hospel

3
Soluzione che utilizza le estensioni di .NET:^(0|9|(?<c>1|(?<c>2|(?<c>3|(?<c>4|(?<c>5|(?<c>6|(?<c>7|(?<c>8))))))))((?<-c>){9})?)*$(?(c).)
Neil,

Risposte:


3

Haskell , 207.535 202.073 byte

5.462 byte salvati utilizzando 0|9invece che [09]dove possibile.

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

Provalo online!

Solo un rapido adattamento della regex data nelle note a piè di pagina dell'articolo collegato per iniziare le cose.

Pastebin di regex di output , per gentile concessione di Herman Lauenstein.

Anche se non sono stato in grado di testare il regex completo, la modifica del programma per verificare la divisibilità per 3 offre invece qualcosa di esattamente equivalente al regex su cui ho basato questo. Inoltre, la modifica del programma per verificare la divisibilità della somma delle cifre per 4 o 5 sembra funzionare anche sui numeri su cui l'ho provato.


Puoi anche testare ciò che il tuo metodo dà per divisibilità per 2 (dovrebbe essere qualcosa di simile /even$/) e divisibilità per 5 (dovrebbe essere qualcosa di simile /[05]$/). PS: menziona la lingua del tuo codice
Ton Hospel,

Ecco un pastebin con l'output (con tutte le occorrenze di ([09]|sostituito con (0|9|per salvare migliaia di byte)
Herman L
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.