È 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).
- Letterali, intervalli di caratteri (
- 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\1
non è 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.
^(0|9|(?<c>1|(?<c>2|(?<c>3|(?<c>4|(?<c>5|(?<c>6|(?<c>7|(?<c>8))))))))((?<-c>){9})?)*$(?(c).)