2016-05-05 13 views
2

Diese Frage ist spezifisch für Java 7/8.Können wir Quantifizierer in einem Lookbehind-Ausdruck verwenden?

Eine ziemlich komplexe Regex, die quantifiers verwendet werden innerhalb Lookbehind Behauptungen wie diesem verboten:

(?<=(a|b*)*)bc 

wie es ergibt sich eine Laufzeitausnahme mit einer Meldung wie:

look-behind group does not have obvious maximum length error 

ich raten bin Dies liegt daran, dass Quantifizierer wie * und + "generell" nicht erlaubt sind.

Allerdings ist die folgende Arbeiten:

(?<=a*)bc 

Warum das so ist?

Es gibt ähnliche Beiträge zu diesem Thema auf SO:

  1. Für andere Sprachen: ruby, PCRE etc-

  2. Einige Beiträge zu Java sind spezifisch, aber scheinen nicht konkret zu bieten Antworten oder Referenzen wie this eins. Meistens sagen die Antworten, dass diese Quantifizierer einfach nicht verwendet werden können. Auch die regular-expressions Website sagt das gleiche.

  3. This post Staaten Java hat Bugs in seinem Blick hinter der Implementierung.

jedoch das Beispiel, das ich oben gezeigt haben, daß verwendet die Null oder viele quantifier * innerhalb des Lookbehind für Java 8.7 gültig ist.

Alle Referenzen oder Erläuterungen wären hilfreich.

+1

(Hinweis: Dies wird nicht von der JLS, sondern von der Bibliotheksdokumentation angegeben.) –

+0

Die [Bibliotheksdokumentation] (http://docs.oracle.com/javase/8/docs/api/java/util/regex /Pattern.html) spezifiziert es auch nicht wirklich. Es verweist auf ein O'Reilly-Buch, das das spezifische Verhalten beschreibt. – ajb

+0

Danke. Ich habe die Korrektur vorgenommen. –

Antwort

1

Nach dem Blick auf den Pattern Code und versuchen, es zu verfolgen, bin ich davon überzeugt, dass dies nur ein Fehler ist. Beide Beispiele sollten zu einer Ausnahme führen. Aber die Logik, die dafür testet, ist falsch.

Dieser Code erscheint in ein paar Plätze:

temp = info.maxLength * cmax + maxL; 
info.maxLength = temp; 
if (temp < maxL) { 
    info.maxValid = false; 
} 

Beachten Sie, dass solange maxLength und cmax nicht negativ sind, temp sollte nie weniger als maxL es sei denn, Überlauf aufgetreten ist. maxValid wird schließlich vom Lookbehind-Code verwendet; Wenn maxValidfalse ist, wird "look-behind group does not have obvious maximum length error" geworfen.

Von dem, was ich in einem regex wie < prefix>< Ausdruck kann sagen>{m,n}, in dem obigen Code ist info.maxLength die maximale Länge der "Expression", cmax die obere Grenze des Quantors ist, und maxL ist die maximale Länge von "Präfix". Wenn ein Quantifizierer * oder + ist, wird die obere Grenze auf Integer.MAX_VALUE festgelegt.(Alle Variablen sind hier int.) Dies bedeutet, dass es einen Überlauf geben wird, es sei denn, info.maxLength ist 1 und maxL ist 0. Das ist genau der Fall mit

(?<=a*)bc 

da das Muster mit der quantifier Länge hat 1, und es gibt nichts, vor dem a* was bedeutet maxL 0 sein wird, das ist, warum dieser Fall fällt durch die Ritzen.

Für alle anderen Werte wird die Berechnung überlaufen, aber das bedeutet nicht notwendigerweise temp < maxL wird wahr. Wenn info.maxLength gerade ist, wird eine Ausnahme ausgelöst. aber wenn info.maxLength ungerade ist, wird das Muster kompiliert, wenn maxL klein genug ist. Dies ist aufgrund der Art und Weise wie Wraparound funktioniert, mathematisch; Der Code, der versucht, auf einen Überlauf zu prüfen, ist ziemlich fehlerhaft. Das bedeutet, dass

(?<=a*)bc   // succeeds 
(?<=(ab)*)bc  // throws exception 
(?<=(abc)*)bc  // succeeds 
(?<=(abcd)*)bc // throws exception 
(?<=(abcde)*)bc // succeeds 

auch:

(?<=xa*)bc  // throws exception 
(?<=x(abc)*)bc // succeeds 

Hinweis: Es sollte in Ihrem Beispiel regex zu beachten, Lookbehind ist nutzlos:

(?<=a*)bc 

Das Lookbehind zu testen, sagt, ob Der aktuellen Position geht kein oder mehrmaliges Vorkommen des Buchstabens a voraus. Das ist immer wahr, trivial. Der Lookbehind hat also keinen Sinn. In ähnlicher Weise

(?<=a+)bc 

entspricht

(?<=a)bc 

da, solange es ein a ist die aktuelle Position der vorhergehenden, spielt es keine Rolle, wie viele es sein könnte. Das gleiche gilt für all Beispiele, die, mit Ausnahme von dieser nicht eine Ausnahme:

(?<=x(abc)*)bc // succeeds 

da hier die Matcher gehen haben nach hinten gesucht abc ‚s in der Zeichenfolge und sicherstellen, dass die letzten Vorangegangen ist x. Es scheint, dass Pattern in diesem Fall eine Ausnahme auslösen sollte, aber wegen der fehlerhaften Überlaufprüflogik ist dies nicht der Fall. Daher bin ich unsicher, ob es tatsächlich das richtige Ergebnis zurückgeben würde oder ob es abstürzen oder in eine Endlosschleife geraten könnte. Ich habe es jedoch nicht ausprobiert.

Wirklich, sollte der Code nur direkt prüfen, ob cmax zu Integer.MAX_VALUE gleich ist, statt es in der Berechnung mit und den Code der Hoffnung, kann später sagen, dass das Ergebnis gefälscht ist.