^((.)(?<!\2.+))*((){7}((?<-4>)(.)(?!(?<-4>.)*\4\6))*)*$
Da dies nur eine einzelne Regex ist, wird Retina im Match-Modus ausgeführt und gibt die Anzahl der gefundenen Matches an, die 1
für gültige Sequenzen und 0
andere gelten. Dies ist im Vergleich zu den Golfsprachen nicht wettbewerbsfähig, aber ich bin ziemlich zufrieden damit, da ich mit einem Monster von 260 Bytes angefangen habe.
Erläuterung
^((.)(?<!\2.+))*
Dieses Bit verwendet ein Präfix aus eindeutigen Buchstaben variabler Länge, dh es entspricht dem möglicherweise unvollständigen führenden Block. Das Lookbehind stellt sicher, dass kein in diesem Bit übereinstimmendes Zeichen zuvor in der Zeichenfolge angezeigt wurde.
Für den Rest der Eingabe möchten wir nun 7er-Blöcke abgleichen, ohne die Zeichen zu wiederholen. Wir könnten so ein Stück zusammenbringen:
(.)(?!.{0,5}\1)(.)(?!.{0,4}\2)(.)(?!.{0,3}\3)...(.)(?!.?\5).
Das heißt, wir stimmen mit einem Zeichen überein, das für weitere 6 Zeichen nicht angezeigt wird, dann mit einem Zeichen, das für weitere 5 Zeichen nicht angezeigt wird, und so weiter. Dies erfordert jedoch eine ziemlich schreckliche Code-Wiederholung, und wir müssten einen nachfolgenden (möglicherweise unvollständigen) Block separat abgleichen.
Ausgleichsgruppen zur Rettung! Eine andere Art zu passen
(.)(?!.{0,5}\1)
Schieben Sie 5 leere Streichhölzer auf einen Erfassungsstapel und versuchen Sie, ihn zu leeren:
(){5}(.)(?!(?<-1>.)*\2)
Das *
erlaubt ein Minimum von null Wiederholungen, genau wie {0,5}
, und da wir fünf Captures verschoben haben, kann es auch nicht mehr als fünf Mal platzen. Dies ist für eine einzelne Instanz dieses Musters länger, aber viel wiederverwendbarer. Da wir das Knallen in einem negativen Lookahead durchführen, wirkt sich dies nicht auf den tatsächlichen Stapel aus, sobald der Lookahead abgeschlossen ist. Nach dem Lookahead haben wir also noch 5 Elemente auf dem Stapel, egal was im Inneren passiert ist. Darüber hinaus können wir einfach vor jedem Lookahead ein Element aus dem Stapel entfernen und den Code in einer Schleife ausführen, um die Lookahead-Breite automatisch von 5 auf 0 zu verringern
(){7}((?<-1>)(.)(?!(?<-1>.)*\1\3))*
(Möglicherweise stellen Sie zwei Unterschiede fest: Wir drücken 7 statt 5. Eine zusätzliche Erfassung besteht darin, dass wir vor jeder Iteration und nicht danach platzen. Die andere ist tatsächlich erforderlich, damit wir sieben Mal vom Stapel springen können (da wir wollen) Wenn die Schleife siebenmal ausgeführt werden soll, können wir diesen Fehler im Lookahead beheben, indem wir sicherstellen, \1
dass noch mindestens ein Element auf dem Stapel vorhanden ist.)
Das Schöne daran ist, dass es auch mit dem nachfolgenden unvollständigen Block übereinstimmen kann, da wir ihn nie siebenmal wiederholen mussten (das ist nur das notwendige Maximum, da wir nicht öfter vom Stapel springen können). Alles, was wir tun müssen, ist, dies in eine andere Schleife zu packen und sicherzustellen, dass wir das Ende der Zeichenfolge erreicht haben, um sie zu erhalten
^((.)(?<!\2.+))*((){7}((?<-4>)(.)(?!(?<-4>.)*\4\6))*)*$