Es ist einfach, eine endliche Zustandsmaschine zu beschreiben, die ein Vielfaches von 9 erkennt: Verfolgen Sie die Ziffernsumme (Mod 9) und addieren Sie die Ziffern, die als nächstes akzeptiert werden. Solch ein FSM hat nur 9 Zustände, sehr einfach! Aufgrund der Äquivalenz zwischen FSM-Erkennbarkeit und regulären Sprachen gibt es einen regulären Ausdruck für ein Vielfaches von 9. Ein solcher regulärer Ausdruck ist jedoch wahrscheinlich ... sehr ... lang. Wie in, wahrscheinlich in der Größenordnung von einem Gigabyte.
Unter https://www.quaxio.com/triple/ finden Sie ein Beispiel für ein Vielfaches von 3. Am Ende der Seite bietet der Autor eine etwas "handoptimierte" Lösung, die etwas kürzer ist als die naive Konvertierung von FSM zu Regex.
Die Herausforderung:
Sie müssen einen regulären Ausdruck erstellen, um ein Vielfaches von 9 zu erkennen. Da ein solcher regulärer Ausdruck voraussichtlich sehr lang ist, bitte ich Sie, ein Programm bereitzustellen, mit dem Sie Ihren regulären Ausdruck ausdrucken können. (Wenn Sie wirklich einen ganzen regulären Ausdruck geben möchten, hosten Sie ihn vielleicht woanders und verlinken Sie ihn hier!)
Sie müssen in der Lage sein, uns die genaue Anzahl der Zeichen für die Ausgabe Ihres Programms mitzuteilen. Ein Programm, das einfach alle regulären Ausdrücke bis zu einer bestimmten Länge ausprobiert, bis es eine funktionsfähige findet, ist nur akzeptabel, wenn es schnell genug ausgeführt wird Führen Sie es vollständig aus und geben Sie uns die resultierende Regex-Länge!
Punkte sind für die kürzeste reguläre Ausgabelänge, natürlich nicht basierend auf der Programmlänge. Da die Regex das "Programm" ist, nach dem ich frage, und es einfach zu lang ist, um es hier bequem zu übertragen, markiere ich immer noch diesen Code-Golf.
Regeln:
- Die Eingabe enthält nur übereinstimmende Zeichen
[0-9]*
. - Ihr regulärer Ausdruck sollte mit einem Vielfachen von 9 übereinstimmen , aber mit nichts anderem. Fälle, die nicht vollständig aus den Ziffern 0-9 bestehen und ungültige Eingaben sind, können nach Belieben übereinstimmen oder fehlschlagen.
- Angesichts der Motivation, dass es von einem DFA leicht erkannt wird, muss der resultierende reguläre Ausdruck in der theoretischeren Terminologie ausgedrückt werden, dh nur Operatoren, unter denen reguläre Sprachen geschlossen sind. Um genau zu sein, die einzigen Dinge, die erlaubt sind:
- Literale, Zeichenbereiche (
[ab]
,[a-f]
,[^k]
), Kleene Stern (*
), Anker (^
und$
) über Klammern Gruppierung, Wechsels (|
), optional Begriffe (?
), ein-oder-mehr Begriffe (+
), Lookaheads ((?=)
), negative Lookaheads ((?!)
), lookbehinds ((?<=)
), negative lookbehinds ((?<!)
), conditionals (wie in https://www.regular-expressions.info/conditional.html -(?(?=test)then|else)
) und Rückverweise von begrenzter Länge (siehe unten).
- Literale, Zeichenbereiche (
- Beispiele für Dinge, die nicht erlaubt sind:
- Rückverweise beliebiger Länge, Vorwärtsverweise, Rekursion, Subroutinen, Schleifenkonstrukte, ausführbarer Code, jede Variation von 'eval' oder eingebaute Konstrukte zum Umwandeln der Zeichenfolge in einen arithmetischen Wert.
- Rückverweise, bei denen gezeigt werden kann, dass sie einen Bindungsstring mit begrenzter Länge aufweisen, sind akzeptabel, da sie in einem endlichen Zustand gespeichert werden können und die Regelmäßigkeit der Sprache nicht ändern. Zum Beispiel ist der reguläre Ausdruck
(..2.[3-5])4\1.\1
akzeptabel, da die Erfassungsgruppe eine begrenzte Länge hat\1
. Dies ist eine reguläre Konstruktion. Ein Konstrukt wie(2*)0\1
ist nicht akzeptabel, da die erfasste Gruppe nicht im endlichen Zustand gespeichert werden kann. - Es steht Ihrem Regex frei, Ganzzahlen mit führenden Nullen nach Belieben zu akzeptieren oder abzulehnen. Die Zeichenfolge
"0"
muss jedoch akzeptiert werden.
^(0|9|(?<c>1|(?<c>2|(?<c>3|(?<c>4|(?<c>5|(?<c>6|(?<c>7|(?<c>8))))))))((?<-c>){9})?)*$(?(c).)