Regex für ein Vielfaches von 9

14

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).
  • 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.\1akzeptabel, da die Erfassungsgruppe eine begrenzte Länge hat \1. Dies ist eine reguläre Konstruktion. Ein Konstrukt wie (2*)0\1ist 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.
Alex Meiburg
quelle
2
Verbunden , nicht sicher, ob dies als Duplikat angesehen wird
ASCII
Ah, hmm! Ich hatte die Suche nach "Regex Multiple", aber nicht "Regex Divisible". Ich nehme an, das ist schrecklich ähnlich, ja.
Alex Meiburg
11
Es wurde noch nicht gesagt, also Willkommen bei PPCG und interessante erste Herausforderung! Wie von einem anderen Benutzer erwähnt, wird häufig empfohlen, aber nicht erforderlich, Challenge-Vorschläge in der Sandbox zu veröffentlichen, damit diese vor dem Posten auf main Feedback erhalten. Dies ist jedoch eine gut durchdachte und klare Herausforderung, sodass es keinen Grund gibt, dies in die Sandbox zu verschieben. Ich hoffe, Sie genießen unsere Community!
Caird Coinheringaahing
Lösungen mit weniger als 200 Kibibyte sind möglich, daher wird es nicht SO groß sein
Ton Hospel
3
Lösung mit den .NET-Erweiterungen:^(0|9|(?<c>1|(?<c>2|(?<c>3|(?<c>4|(?<c>5|(?<c>6|(?<c>7|(?<c>8))))))))((?<-c>){9})?)*$(?(c).)
Neil

Antworten:

3

Haskell , 207.535, 202.073 Bytes

5.462 Bytes werden durch Verwendung 0|9von gespeichert, [09]wo dies möglich ist.

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

Probieren Sie es online!

Nur eine schnelle Anpassung des regulären Ausdrucks in den Fußnoten des verlinkten Artikels, um den Anfang zu machen.

Pastebin von Output Regex , mit freundlicher Genehmigung von Herman Lauenstein.

Obwohl ich nicht in der Lage war, die vollständige Regex zu testen, ergibt eine Änderung des Programms, um die Teilbarkeit durch 3 zu überprüfen, etwas, das genau der Regex entspricht, auf der ich diese basiert habe. Darüber hinaus scheint das Ändern des Programms, um die Teilbarkeit der Ziffernsumme durch 4 oder 5 zu überprüfen, auch auf den Zahlen zu funktionieren, auf denen ich es getestet habe.

Nitrodon
quelle
Sie können auch testen, wie Ihre Methode die Teilbarkeit durch 2 (sollte ungefähr so ​​sein /even$/) und die Teilbarkeit durch 5 (sollte ungefähr so ​​sein /[05]$/) angibt . PS: Erwähnen Sie die Sprache Ihres Codes
Ton Hospel
Hier ist ein Pastebin mit der Ausgabe (mit allen Vorkommen von ([09]|ersetzt (0|9|, um Tausende von Bytes zu sparen)
Herman L