2010-04-29 7 views
10

Können Sie Rückverweise in einem Lookbehind verwenden?Rückverweise in Lookbehind

Lassen Sie uns sagen, ich möchte split wo immer hinter mir ein Zeichen zweimal wiederholt wird.

String REGEX1 = "(?<=(.)\\1)"; // DOESN'T WORK! 
    String REGEX2 = "(?<=(?=(.)\\1)..)"; // WORKS! 

    System.out.println(java.util.Arrays.toString(
     "Bazooka killed the poor aardvark (yummy!)" 
     .split(REGEX2) 
    )); // prints "[Bazoo, ka kill, ed the poo, r aa, rdvark (yumm, y!)]" 

Mit REGEX2 (wo ist die Rückreferenzierung in einem Look-Ahead in einem Lookbehind verschachtelt) funktioniert, aber REGEX1 gibt diesen Fehler zur Laufzeit:

Look-behind group does not have an obvious maximum length near index 8 
(?<=(.)\1) 
     ^

Diese Art Sinn machen, ich Angenommen, die Rückreferenz kann im Allgemeinen eine Zeichenfolge beliebiger Länge erfassen (wenn der Regex-Compiler ein bisschen schlauer ist, könnte es jedoch in diesem Fall \1(.) bestimmen und hat daher eine endliche Länge).

Gibt es also eine Möglichkeit, eine Rückreferenz in einem Lookbehind zu verwenden?

Und wenn nicht, können Sie immer mit diesem verschachtelten Lookahead umgehen? Gibt es andere gebräuchliche Techniken?

+1

Interessant und +1 für Ihre geniale Problemumgehung. Ich benutze kein Java, also kann ich es nicht selbst ausprobieren - was passiert, wenn die rückreferenzierte Gruppe außerhalb des Lookarounds ist, wie '(? <= \\ 1) (.)'? –

+0

@Tim: Es ergibt sich im Wesentlichen die gleiche 'PatternSyntaxException'. By the way, wenn jemand mit einer Variante dieses Problems herumspielen will, habe ich nur eine auf codingBat geschrieben: http://codingbat.com/prob/p266235 – polygenelubricants

+0

@polygene lubricants Ich wünschte, ich könnte diese Regex upvote: (? <= (? = (.) \\ 1) ..) für mindestens 10 mal. sehr elegant! – Eugene

Antwort

5

Sieht so aus, als ob Ihr Verdacht richtig ist, dass Rückreferenzen im Allgemeinen nicht in Java-Lookbehinds verwendet werden können. Die von dir vorgeschlagene Problemumgehung macht die endliche Länge des Lookbehinds explizit und sieht für mich sehr clever aus.

Ich war fasziniert herauszufinden, was Python mit dieser Regex macht. Python unterstützt nur Look-Behind fester Länge, nicht endliche Länge wie Java, aber diese Regex ist eine feste Länge. Ich konnte re.split() nicht direkt verwenden, weil Python re.split() nie auf einem leeren Spiel spaltet, aber ich denke, ich habe einen Fehler in re.sub() gefunden:

>>> r=re.compile("(?<=(.)\\1)") 
>>> a=re.sub(r,"|", "Bazooka killed the poor aardvark (yummy!)") 
>>> a 
'Bazo|oka kil|led the po|or a|ardvark (yum|my!)' 

Das Lookbehind Spiele zwischen die beiden doppelten Zeichen!

+0

Sehen Sie http://stackoverflow.com/questions/2628534/codingbat-plusout-using-regex für mehr Regex-Spaß. – polygenelubricants

+0

Das ist dumm, dass 're.split()' sich nicht auf ein leeres Spiel teilt. Warum zum Teufel würden sie es so machen? Ich würde denken, dass es viele Male gibt, die Sie einfach basierend auf Behauptungen anstelle von tatsächlichen nicht leeren Trennzeichen trennen möchten. – polygenelubricants

+0

Ich habe die gleiche Sache auf dem Python Bugtracker gefragt. Es war wahrscheinlich nicht beabsichtigt, wird aber in Ruhe gelassen, um Kompatibilitätsprobleme nicht zu verursachen; Es gibt eine große Regex-Engine-Überholung, aber es kann eine Weile dauern, bis das neue Regex-Modul in die Standardbibliothek integriert ist. –