Избегайте совпадения регулярных выражений в Java - PullRequest
4 голосов
/ 27 ноября 2010

По какой-то причине этот фрагмент кода 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 ]

2 голосов
/ 30 ноября 2010

Использование вами слова «перекрытие» сбивает с толку. Очевидно, вы имели в виду, что регулярное выражение слишком жадное и соответствует всему от первого leftContext до последнего rightContext. Кажется, вы уже поняли это - и придумали лучший подход - но есть еще как минимум одна потенциальная проблема.

Вы сказали, что leftContext и rightContext являются "простыми строками", и я предполагаю, что вы подразумевали, что они не должны интерпретироваться как регулярные выражения, но они будут. Вы должны избегать их, или любые метасимволы регулярных выражений, которые они содержат, приведут к неверным результатам или исключениям времени выполнения. То же самое относится и к вашей заменяющей строке, хотя только $ и обратный слеш имеют особое значение. Вот пример (обратите внимание на не жадного .*? тоже):

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 вместо того, чтобы свернуть свои собственные с appendReplacement и appendTail:

return input.replaceAll("(?s)(" + lcRegex + ")" +
                        "(?:(?!" + rcRegex + ").)*" +
                        "(" + rcRegex + ")",
    "$1" + replace + "$2");
1 голос
/ 27 ноября 2010

Возможностей мало, в зависимости от того, что вам действительно нужно.

Вы можете добавить $ в конце своего регулярного выражения, например:

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

, поэтому, если rightContext не последнее, ваше регулярное выражение не будет соответствовать.

Далее вы можете захватить все после rightContext:

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

и после этого откажитесь от всего в вашей третьей соответствующей группе.

Но, поскольку мы не знаем, что на самом деле являются leftContext и rightContext, возможно, ваша проблема заключается в них.

...