2010-11-27 19 views
4

Aus irgendeinem Grund dieses Stück Java-Code gibt mir überlappende Spiele:Vermeiden überlappende Regex Matching in Java

Pattern pat = Pattern.compile("(" + leftContext + ")" + ".*" + "(" + rightContext + ")", Pattern.DOTALL); 

jede mögliche Weise/Option, so dass es Überschneidungen Erkennung vermeidet? z.B. leftContext rightContext rightContext sollte anstelle von 2

Hier sein 1 Begegnung ist der vollständige Code:

public static String replaceWithContext(String input, String leftContext, String rightContext, String newString){ 
    Pattern pat = Pattern.compile("(" + leftContext + ")" + ".*" + "(" + rightContext + ")", Pattern.DOTALL); 
    Matcher matcher = pat.matcher(input); 
    StringBuffer buffer = new StringBuffer(); 

    while (matcher.find()) { 
    matcher.appendReplacement(buffer, ""); 
    buffer.append(matcher.group(1) + newString + matcher.group(2)); 
    } 
    matcher.appendTail(buffer); 

    return buffer.toString(); 
} 

Also hier ist die endgültige Antwort eine negative Vorschau verwenden, meine schlecht für nicht ahnend * gierig war:

Pattern pat = Pattern.compile("(" + 
    leftContext + ")" + "(?:(?!" + 
    rightContext + ").)*" + "(" + 
    rightContext + ")", Pattern.DOTALL); 
+1

können Sie uns sagen, was leftContext und rightContext sind? Und geben Sie uns ein Beispiel für ein fehlgeschlagenes Spiel. – marcog

+1

Den Regex-Matcher zu erfassen, um überlappende Dinge zu erfassen, ist normalerweise eine etwas knifflige Angelegenheit, nicht etwas, was standardmäßig passiert. Ohne den Inhalt der Muster zu sehen, ist es schwer zu sagen, was passiert. Es würde grundsätzlich Lookarounds erfordern, damit der Matcher mehr als einmal über den gleichen Teil der Saite gehen kann. Machst du das? – tchrist

+0

rightContext und leftContext sind einfache Strings e.g leftContext = "ab" rightContext = "cd" – Ricardo

Antwort

2

Ihre Verwendung des Wortes "überlappend" ist verwirrend. Anscheinend war das, was Sie meinten, dass die Regex zu gierig ist und alles von der ersten leftContext bis zur letzten rightContext zusammenpasst. Es scheint, dass du das bereits herausgefunden hast - und auch einen besseren Ansatz gefunden hast -, aber es gibt immer noch mindestens ein potenzielles Problem.

Sie sagte leftContext und rightContext sind „plain Strings“, von dem ich nehme an, Sie bedeutete, dass sie als reguläre Ausdrücke nicht interpretiert werden sollen, aber sie werden. Sie müssen ihnen ausweichen, oder alle Regex-Metazeichen, die sie enthalten, führen zu falschen Ergebnissen oder Laufzeitausnahmen. Das gleiche gilt für Ihre Ersatzzeichenfolge, obwohl nur $ und der Backslash dort besondere Bedeutungen haben. Hier ist ein Beispiel (man beachte die nicht gierigen .*? auch):

public static String replaceWithContext(String input, String leftContext, String rightContext, String newString){ 
    String lcRegex = Pattern.quote(leftContext); 
    String rcRegex = Pattern.quote(rightContext); 
    String replace = Matcher.quoteReplacment(newString); 
    Pattern pat = Pattern.compile("(" + lcRegex + ").*?(" + rcRegex + ")", Pattern.DOTALL); 

Eine andere Sache: wenn Sie keine post-match-Verarbeitung auf dem angepassten Text zu tun sind, können Sie replaceAll verwenden, anstatt Ihre eigene Walz mit appendReplacement und appendTail:

return input.replaceAll("(?s)(" + lcRegex + ")" + 
         "(?:(?!" + rcRegex + ").)*" + 
         "(" + rcRegex + ")", 
    "$1" + replace + "$2"); 
1

Es gibt wenige Möglichkeiten, je nachdem, was Sie wirklich brauchen.

Sie $ am Ende Ihrer Regex anhängen kann, wie folgt aus:

"(" + leftContext + ")" + ".*" + "(" + rightContext + ")$" 

also, wenn rightContext nicht das letzte, was ist, wird Ihre regex passen nicht zusammen.

Als nächstes können Sie alles nach rightContext erfassen:

"(" + leftContext + ")" + ".*" + "(" + rightContext + ")(.*)" 

und dass nach allem, was in der dritten passende Gruppe verwerfen.

Aber da wir nicht wissen, was leftContext und rightContext wirklich sind, vielleicht liegt Ihr Problem in ihnen.

+0

mm, nicht sicher, wie das in meinem Code funktioniert, kann ich nicht einfach Teile der Eingabezeichenfolge verwerfen – Ricardo