Negative Lookahead-Assertion mit dem Modifizierer * in Perl

7

Ich habe die (was ich glaube) negative Lookahead-Assertion <@> *(?!QQQ) , mit der ich übereinstimme, wenn die getestete Zeichenfolge ein <@> gefolgt von einer beliebigen Anzahl von Leerzeichen ist (einschließlich Null) und dann nicht gefolgt von QQQ .

Wenn die getestete Zeichenfolge jedoch <@> QQQ ist, stimmt der reguläre Ausdruck überein.

Ich verstehe nicht, warum dies der Fall ist, und würde mich über jede Hilfe in dieser Angelegenheit freuen.

Hier ist ein Testskript

%Vor%

Dies druckt

%Vor%

Und ich hätte erwartet, dass die erste Zeile something <@> QQQ --> something at w/ QQQ wäre.

    
René Nyffenegger 27.04.2012, 11:45
quelle

3 Antworten

10

Es stimmt überein, weil Null in "beliebige Anzahl" enthalten ist. Also keine Leerzeichen, gefolgt von einem Leerzeichen, "entspricht einer beliebigen Anzahl von Leerzeichen, auf die kein Q folgt".

Sie sollten eine weitere Lookahead-Assertion hinzufügen, die als erstes nach Ihren Leerzeichen kein Leerzeichen ist. Probieren Sie dies (ungetestet):

%Vor%

ETA Randnotiz: Wenn Sie den Quantifizierer in + ändern, wäre dies nur hilfreich, wenn genau ein Leerzeichen vorhanden ist. Im allgemeinen Fall kann die Regex immer einen Platz weniger nehmen und daher erfolgreich sein. Regexes wollen übereinstimmen und werden sich nach hinten beugen, um dies auf jede mögliche Weise zu tun. Alle anderen Überlegungen (am weitesten links, am längsten usw.) treten in den Hintergrund - wenn sie mehr als einen Weg finden können, bestimmen sie, welcher Weg gewählt wird. Aber das Matching gewinnt immer, wenn es nicht passt.

    
Mark Reed 27.04.2012, 11:53
quelle
7
%Vor%

Ein Problem von Ihnen besteht darin, dass Sie die beiden Regexes getrennt betrachten. Sie bitten zuerst, die Zeichenfolge ohne QQQ zu ersetzen und dann die Zeichenfolge durch QQQ zu ersetzen. Dies überprüft in gewisser Weise das Gleiche zweimal. Zum Beispiel: if (X==0) { ... } elsif (X!=0) { ... } . Mit anderen Worten, der Code könnte besser geschrieben werden:

%Vor%

Sie müssen immer vorsichtig mit dem * Quantor umgehen. Da es null oder mehr Male übereinstimmt, kann es auch der leeren Zeichenfolge entsprechen, was im Grunde bedeutet: Es kann jede Stelle in einer beliebigen Zeichenfolge übereinstimmen.

Eine negative Look-Around-Behauptung hat eine ähnliche Qualität in dem Sinne, dass sie nur eine einzige Sache finden muss, die sich unterscheidet, um zu passen. In diesem Fall entspricht es dem Teil "<@> " als <@> + kein Leerzeichen + Leerzeichen, wobei der Platz natürlich "nicht" QQQ ist. Sie befinden sich mehr oder weniger in einer logischen Sackgasse, weil sich der * Quantor und das negative Look-ahead gegenseitig bedrohen.

Ich glaube, der richtige Weg, dies zu lösen, ist, die Regexe zu trennen, wie ich oben gezeigt habe. Es hat keinen Sinn zuzulassen, dass beide Regexes ausgeführt werden können.

Aber für theoretische Zwecke müsste eine funktionierende Regex, die sowohl eine beliebige Anzahl von Leerzeichen, als auch eine negative Vorausschau erlaubt, verankert werden. Ähnlich wie Mark Reed gezeigt hat. Dieser könnte der einfachste sein.

%Vor%

Der Unterschied besteht darin, dass die Leerzeichen und Qs nun miteinander verankert sind, während sie zuvor noch getrennt sein konnten. Um den Punkt des * Quantors nach Hause zu bringen und ein kleines Problem beim Entfernen zusätzlicher Leerzeichen zu lösen, können Sie Folgendes verwenden:

%Vor%

Dies wird funktionieren, weil einer der Quantifizierer mit der leeren Zeichenfolge übereinstimmen kann. Theoretisch können Sie so viele hinzufügen, wie Sie möchten, und das macht keinen Unterschied (außer in der Leistung): / * * * * * * */ ist funktional äquivalent zu / */ . Der Unterschied hier ist, dass Leerzeichen mit Qs nicht existieren können.

    
TLP 27.04.2012 14:09
quelle
4

Die Regex-Engine wird zurückverfolgt, bis sie eine Übereinstimmung findet oder bis das Finden einer Übereinstimmung unmöglich ist. In diesem Fall hat es die folgende Übereinstimmung gefunden:

%Vor%

Alles, was Sie tun müssen, ist Dinge zu mischen. Ersetzen Sie

%Vor%

mit

%Vor%

Oder Sie können es so machen, dass die Regex nur mit allen Leerzeichen übereinstimmt:

%Vor%

PS - Leerzeichen sind schwer zu sehen, daher verwende ich [ ] , um sie besser sichtbar zu machen. Es wird sowieso weg optimiert.

    
ikegami 27.04.2012 15:17
quelle