Wie schreibe ich einen Ausdruck, der genau N Wiederholungen des gleichen Zeichens (oder im Idealfall der gleichen Gruppe) entspricht? Im Grunde genommen, was (.){N-1}
tut, aber mit einer wichtigen Einschränkung: Der Ausdruck sollte fehlschlagen, wenn das Thema wiederholt wird more als N-mal. Wenn Sie beispielsweise N=4
und die Zeichenfolge xxaaaayyybbbbbzzccccxx
angeben, sollten die Ausdrücke mit aaaa
und cccc
und nicht mit bbbb
übereinstimmen.
Ich konzentriere mich nicht auf einen bestimmten Dialekt, sondern benutze jede Sprache. Bitte schreiben Sie keinen Code, der nur für dieses spezielle Beispiel funktioniert, ich suche nach einer allgemeinen Lösung.
Verwenden Sie negatives Lookahead und negatives Lookbehind.
Das wäre die Regex: (.)(?<!.){N-1}(?!)
, außer dass Pythons re-Modul kaputt ist (siehe dies link ).
Englische Übersetzung: "Entsprechen Sie einem beliebigen Zeichen. Achten Sie darauf, dass das Zeichen vor dem Zeichen nicht dasselbe ist. Entsprechen Sie N-1 mehr Wiederholungen dieses Zeichens. Stellen Sie sicher, dass das Zeichen nach diesen Wiederholungen ist nicht auch dieses Zeichen. "
Leider ist das re-Modul (und die meisten regulären Ausdrucksmodule) defekt, da Sie keine Rückverweise in einer Lookbehind-Assertion verwenden können. Lookbehind-Assertionen müssen eine konstante Länge haben, und die Compiler sind nicht schlau genug, um daraus abzuleiten, dass eine Backreference verwendet wird (obwohl, wie in diesem Fall, die Backref von konstanter Länge ist). Wir müssen den Regex-Compiler wie folgt behandeln:
Die tatsächliche Antwort muss unordentlicher sein: r"(.)(?<!(?=)..){N-1}(?!)"
Dies funktioniert um den Fehler im re-Modul herum, indem (?=)..
anstelle von .
verwendet wird (diese sind meistens äquivalent). Dadurch kann die Regex-Engine genau die Breite der Lookbehind-Assertion kennen, so dass sie funktioniert PCRE und re und so weiter.
Natürlich ist eine reale Lösung etwas wie [x.group() for x in re.finditer(r"(.)*", "xxaaaayyybbbbbzzccccxx") if len(x.group()) == 4]
Ich vermute, dass Sie ein negatives Lookahead verwenden möchten: (.){N-1}(?!)
.
Aber das sagte ... Ich vermute, dass die einfachste sprachübergreifende Lösung ist, schreiben Sie sie einfach selbst, ohne Regexes zu verwenden.
UPDATE:
^(.)\1{3}(?!\1)|(.)(?<!(?=\2)..)\2{3}(?!\2)
funktioniert für mich allgemeiner, einschließlich Übereinstimmungen, die am Anfang der Zeichenfolge beginnen.
Es ist leicht, reguläre Ausdrücke zu sehr zu belasten und sie dazu zu bringen, alles zu tun, wenn nur fast alles tut!
Verwenden Sie eine Regex, um alle Teilstrings zu finden, die aus einem einzelnen Zeichen bestehen, und überprüfen Sie dann ihre Länge wie folgt:
%Vor%Ausgabe
%Vor%Die Regex-Engine von Perl unterstützt kein Lookbehind mit variabler Länge, daher müssen wir darüber nachdenken.
%Vor%Einige Testfälle:
%Vor%Ausgabe:
%Vor%Es ist ein lustiges Puzzle, aber Ihre regex-averse Kollegen werden wahrscheinlich unglücklich sein, wenn eine solche Konstruktion im Produktionscode auftaucht.
Wie wäre es mit Python?
%Vor%Testen mit Ihrer Zeichenfolge in verschiedenen Größen:
%Vor%Die erste Schleife teilt den Text grundsätzlich in Teile auf: ["xx", "aaaa", "yyy", "bbbbb", "zz", "cccc", "xx"]. Dann testet die zweite Schleife diese Teile auf ihre Länge. Am Ende gibt die Funktion nur die Teile zurück, die die aktuelle Länge haben. Ich bin nicht der Beste bei der Erklärung von Code, also ist es jedem freigestellt, diese Erklärung bei Bedarf zu verbessern.
Wie auch immer, ich denke, das wird reichen!
Warum lassen Sie die Engine nicht so lange regulieren, wie es am besten funktioniert - Sie finden die längste Zeichenfolge mit den gleichen Symbolen und überprüfen dann die Länge selbst.
In Perl:
%Vor%