避免在Java中重叠正则表达式匹配

时间:2010-11-27 08:16:53

标签: java regex matcher

由于某种原因,这段Java代码给了我重叠的匹配:

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

任何方式/选项,以避免检测重叠?例如 leftContext rightContext rightContext 应该是1匹配而不是2

这是完整的代码:

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();
 }

所以这是使用否定前瞻的最终答案,我不认识*是贪婪的:

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

2 个答案:

答案 0 :(得分:2)

您对“重叠”一词的使用令人困惑。显然,你的意思是正则表达式太贪婪,匹配从第一个leftContext到最后一个rightContext的所有内容。看起来你已经知道了 - 并且提出了一个更好的方法 - 但仍然至少存在一个潜在的问题。

你说leftContextrightContext是“简单的字符串”,我认为你的意思是它们不应该被解释为正则表达式,但它们将是。您需要转义它们,或者它们包含的任何正则表达式元字符都会导致错误的结果或运行时异常。对于替换字符串也是如此,尽管只有$和反斜杠具有特殊含义。这是一个例子(注意非贪婪的.*?):

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);

另一件事:如果您没有对匹配的文字进行任何匹配后处理,则可以使用replaceAll而不是使用appendReplacementappendTail滚动自己的匹配:< / p>

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

答案 1 :(得分:1)

根据你真正需要的东西,几乎没有可能。

您可以在正则表达式的末尾添加$,如下所示:

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

所以如果rightContext不是最后一件事,你的正则表达式将不匹配。

接下来,您可以在rightContext之后捕获所有内容:

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

然后丢弃第三个匹配组中的所有内容。

但是,既然我们不知道leftContextrightContext到底是什么,也许你的问题就在其中。

相关问题