2015-09-29 13 views
7

Leute, Ich versuche, reguläre Ausdrücke zu verwenden, um eine große Reihe von Zahlenfolgen zu verarbeiten und Ziffernfolgen für bestimmte Muster, wo einige Ziffern sind in Gruppen wiederholt. Ein Teil der Anforderung besteht darin, die Eindeutigkeit zwischen den Abschnitten des gegebenen Musters sicherzustellen.Regex entspricht zwei Gruppen von sich wiederholenden Ziffern, wobei beide nicht die gleichen Ziffern sein dürfen

Ein Beispiel für die Art, wie ich passender ist versucht

ABBBCCDD 

Interpretieren dies als eine Reihe von Ziffern zu erreichen. Aber A, B, C, D können nicht gleich sein. Und die Wiederholung von jedem ist das Muster, dem wir zu entsprechen versuchen.

Ich habe reguläre Ausdrücke mit negativem Look-Ahead als Teil dieses Matching verwendet und es funktioniert aber nicht die ganze Zeit und ich bin verwirrt, warum. Ich hoffe, dass jemand erklären kann, warum es schief geht und eine Lösung vorschlägt.

So ABBBCCDD Adresse ich mit dieser RE mit negativem Vorgriff unter Verwendung von Gruppen kam ..

(.)(?!\1{1,7})(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1} 

Um dies zu brechen ..

(.)   single character wildcard group 1 (A) 
(?!\1{1,7}) negative look-ahead for 1-7 occurrences of group 1 (A) 
(.)   single character wildcard group 2 (B) 
\2{2}   A further two occurrences of group 2 (B) 
(?!\2{1,4}) Negative look-ahead of 1-4 occurrences of group 2 (B) 
(.)   single character wildcard group 3 (C) 
\3{1}   One more occurrence of group 3 (C) 
(?!\3{1,2}) Negative look-ahead of 1-2 occurrences of group 3 (C) 
(.)   single character wildcard group 4 (D) 
\4{1}   one more occurrence of group 4 (D) 

Die hier denkt, dass die negativen Look-Ahead-Funktionen dienen dazu, zu überprüfen, ob ein bestimmtes Zeichen dort gefunden wird, wo es unerwartet ist. Also wird A in den nächsten 7 Zeichen überprüft. Sobald B und seine 2 Wiederholungen übereinstimmen, schauen wir negativ auf B in den nächsten 4 Zeichen. Schließlich, sobald das Paar von Cs abgestimmt ist, suchen wir in den letzten 2 nach einem C, um eine Nichtübereinstimmung zu erkennen.

Für Testdaten entspricht diese Zeichenfolge "01110033" dem Ausdruck. Aber es sollte nicht, weil die '0' für A in der C-Position wiederholt wird.

Ich überprüfte diesen Ausdruck in Python und mit grep im PCRE-Modus (-P). Beide stimmten mit dem falschen Muster überein.

Ich legte den Ausdruck in https://regex101.com/ zusammen mit dem gleichen Test-String "01110033" und es auch dort abgestimmt. Ich habe keine ausreichende Bewertung, um Bilder davon oder von Variationen, die ich mit den Testdaten versucht habe, zu veröffentlichen. So sind hier einige Texte Grabs von Kommandozeilen-Läufen mit grep -P

so unserem ungültigen Ausdruck, dass A in CC wiederholt Position durch bekommt ..

$ echo "01110033" | grep -P '(.)(?!\1{1,7})(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}' 
01110033 
$ 

Ändern DD bis 11, das Kopieren von BBB, wir auch feststellen, dass wird eine Vorwärts negative Kontrolle, durch trotz B ..

$ echo "01110011" | grep -P '(.)(?!\1{1,7})(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}' 
01110011 
$ 

Jetzt DD ändern auf „00“, das Kopieren die CC Ziffern und siehe da es nicht .. überein

$ echo "01110000" | grep -P '(.)(?!\1{1,7})(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}' 
$ 

Löschen Sie die Forward-Negative-Prüfung für CC "(?! \ 3 {1,2})" aus dem Ausdruck und unsere Wiederholung der C-Ziffer in der D-Position macht es durch.

$ echo "01110000" | grep -P '(.)(?!\1{1,7})(.)\2{2}(?!\2{1,4})(.)\3{1}(.)\4{1}' 
01110000 
$ 

Zurück zu den ursprünglichen Prüfnummer und Schalter CC Ziffern auf die gleiche Verwendung von ‚1‘ von B. Es irgendeinem Grund nicht bekommen.

$ echo "01111133" | grep -P '(.)(?!\1{1,7})(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}' 
$ 

Und dies für die BBB Gruppe zu spielen, die B Ziffern auf die gleiche 0 gesetzt, wie angetroffen nicht für A. Auch übereinstimmen ..

$ echo "00002233" | grep -P '(.)(?!\1{1,7})(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}' 
$ 

dann die negative Vorschau nehmen für A, und wir können dieses übereinstimmen ..

$ echo "00002233" | grep -P '(.)(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}' 
00002233 
$ 

So scheint es mir, dass die vorwärts-negative Kontrolle funktioniert, aber dass es funktioniert nur mit der nächsten benachbarten Reihe oder der vorgesehene Look-Ahead-Bereich ist kurz geschnitten in einigen für Vermutlich durch die zusätzlichen Dinge, die wir versuchen zu erreichen.

Wenn ich einen zusätzlichen Look-Ahead auf der A direkt nach B und seine Wiederholung hinzufügen verarbeitet worden ist, bekommen wir es auf dem CC Teil der A Ziffer Wiederverwendung zu vermeiden passenden ..

$ echo "01110033" | grep -P '(.)(?!\1{1,7})(.)\2{2}(?!\1{1,4})(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1}' 
$ 

dies weiter zu nehmen, Nach dem Abgleich des CC-Sets müsste ich dann die negativen Lookaheads für A und B wiederholen. Das scheint einfach falsch zu sein.

Hoffentlich ein RE-Experte kann klären, was ich hier falsch machen oder bestätigen, wenn die negative Lookahead in der Tat auf der Grundlage begrenzt ist, was ich beobachtet

Antwort

0
(.)(?!.{0,6}\1)(.)\2{2}(?!\2{1,4})(.)\3{1}(?!\3{1,2})(.)\4{1} 

    ^^^^^^^^ 

ändern lookahead Spiel zu verbieten, wenn \1 überall erscheint in der string.Sehen Sie demo.You können in ähnlicher Weise andere Teile auch in Ihrem Regex ändern.

https://regex101.com/r/vV1wW6/31

+0

Vielen Dank dafür. Das wird speziell für das Beispiel funktionieren, das ich gezeigt habe. Einige der ausgeklügelteren Muster wiederholen jedoch A, B, C, D später in der Sequenz. Aber basierend auf Ihrer Antwort habe ich gerade gefunden, dass die Verwendung von .. (?!. {0,6} \ 1) auch als Mittel zum Testen meiner Gruppe in den nächsten 7 Zeichen funktionieren würde, indem Sie es als 0-6 Wildcards setzen nach meinem Gruppencharakter. Also werde ich mit diesem Ansatz vorerst laufen. Nochmals vielen Dank für die schnelle Antwort. –

0

HINWEIS: aktualisiert.

Wie bereits erwähnt, waren Ihre negativen Lookaheads nicht ausgeschlossen, was Sie dachten - \1{1,7} zum Beispiel wird nur A, AA, AAA, AAAA, AAAAA, AAAAAA und AAAAAAA ausschließen. Ich glaube, Sie die Lookaheads wollen .*\1 sein, .*\2, .*\3 usw.

Aber hier ist eine andere Idee: Es ist einfach, jede Zeile Vorfilter aus, die nicht benachbarte wiederholten Zeichen hat:

grep -P -v '(.)(?!\1).*\1' 

und dann regexp auf dem Ergebnis ist viel einfacher: .{1}.{3}.{2}.{2}

in der Tat Und das ganze kann mit dem ersten als negativer pre-Look-Ahead-Einschränkung kombinierbar:

(?!.*(.)(?!\1).*\1).{1}.{3}.{2}.{2} 

Oder wenn Sie brauchen, um die Ziffern zu erfassen, wie Sie ursprünglich tun:

(?!.*(.)(?!\1).*\1)(.){1}(.){3}(.){2}(.){2} 

Aber beachten Sie, dass diese Ziffern werden nun \ 2 \ 3 \ 4 \ 5, sein, da \ 1 in dem Look-Ahead ist.

+1

Danke für diese Klarstellung. Es gibt eine Reihe von über 50 Mustern, die ich anpassen muss und sie gehen überall mit den Mustern. In einigen Fällen wird das gleiche Zeichen weiter wiederholt. Also musste ich die Lösung von vks modifizieren, um (?!. {0,6} \ 1) zu sein, was auf 0-6 Wilds gefolgt von \ 1 als Ersatz für das, was ich dachte \ 1 {1,7}, getestet wurde sollte für mich tun. Und die anderen Ausdrücke wurden dann einfach Varianten desselben Tricks –

+0

Gern geschehen. Das ist die Sache - ein Überblick über den _complete_ Problembereich ist, was Sie/wir brauchen, bevor eine allgemein korrekte Lösung gefunden werden kann. Und wenn es wirklich "überall mit den Mustern" ist, gibt es keine allgemeine Lösung - du musst es Stück für Stück machen. –

0

Basierend auf der bisherigen Rückmeldung gebe ich eine weitere Antwort, die nicht auf einer arithmetischen Gesamtlänge beruht und die jede Sequenz von 4 eindeutigen Zeichen-/Zifferngruppen in der Längensequenz 1 identifiziert. 3,2,2 irgendwo in einer Zeichenfolge:

/(?<=^|(.)(?!\1))(.)\2{0}(?!\2)(.)\3{2}(?!\2|\3)(.)\4{1}(?!\2|\3|\4)(.)\5{1}(?!\5)/gm 
^^^^^^^^^^^^^^^^ this is a look-behind that makes sure we're starting with a new character/digit 
       ^^^^^^^^ this is the size-1 group; yes the \2{0} is superfluous 
         ^^^^^^ this ensures the next group is unique 
           ^^^^^^^^ this is the size-3 group 
etc. 

Lassen Sie mich wissen, wenn dies näher an Ihrer Lösung ist. Wenn ja, und wenn alle Ihre "Patterns" aus Sequenzen der Gruppengrößen bestehen, nach denen Sie suchen (wie 1,3,2,2), kann ich einen Code erstellen, der die entsprechende Regexp für einen solchen generiert Eingabe "Muster".

0

nur einige Details hier auf, was die letztendliche Lösung wie für mich sah ..

Also im Grunde (?! \ 1 {1,7}) war nicht, was ich gedacht hatte, wäre es und war die ganze Sache von den Problemen, die ich angetroffen hatte. Ich danke Ihnen, dass Sie dieses Problem für mich gefunden haben.

Das Beispiel, das ich gezeigt hatte, war 1 von ungefähr 50, die ich von einer Reihe von Mustern formulieren musste.

Es endete als ..

ABBBCCDD 
09(.)(?!.{0,6}\1)(.)\2{2}(?!.{0,3}\2)(.)\3{1}(?!.{0,1}\3)(.)\4{1} 

So einmal \ 1 (A) wurde erfasst, I negativ getestet Vorgriffs-von 0-6 wildchars vorhergehenden A. Dann erfassen I \ 2 (B), seine beiden Wiederholungen und geben Sie dann B negative Vorausschau von 0-3 Wilds + B und so weiter.

Es konzentriert den Fokus darauf, nach vorne zu schauen, um sicherzustellen, dass sich die gefangenen Gruppen nicht dort wiederholen, wo sie nicht sollten. Dann werden die nachfolgenden Aufnahmen und ihre Wiederholungsmuster den Rest übernehmen, um die Übereinstimmung sicherzustellen.

Weitere Beispiele aus dem letzten Satz:

ABCCDDDD 
(.)(?!.{0,6}\1)(.)(?!.{0,5}\2)(.)\3{1}(?!.{0,3}\3)(.)\4{3} 

AABBCCDD 
(.)\1{1}(?!.{0,5}\1)(.)\2{1}(?!.{0,3}\2)(.)\3{1}(?!.{0,1}\3)(.)\4{1} 

ABCCDEDE 
09(.)(?!.{0,6}\1)(.)(?!.{0,5}\2)(.)\3{1}(?!.{0,3}\3)(.)(?!\4{1})(.)\4{1}\5{1}