Странное позитивное поведение Lookahead в движке java.util.regex - PullRequest
1 голос
/ 15 февраля 2011

У меня есть текст со многими животными видов цертина и некоторыми ловушками, и другой текст без значения, например, "cat dog house 131 bird 1341 house trap cat cat cat dog trap house dog house trap".

Я пытаюсь построить регулярное выражение, которое найдет животное с ближайшим приоритетом для каждой ловушки, например, "кошачья собака домик 131 птица 1341 домик ловушка кошка кошка кошка собака ловушка дом собака дом ловушка ".

Я написал это регулярное выражение: (cat|dog|bird)(?!.*(cat|dog|bird).*).*trap

и вот мой полный Java-код:

Pattern p = Pattern.compile("(cat|dog|bird)(?!.*(cat|dog|bird).*).*trap");
Matcher m = p.matcher("cat dog house 131 bird 1341 house trap cat cat cat dog trap house dog house trap");
int start = 0;
while (m.find(start)) {
    System.out.println(m.group(0));
    System.out.println(m.group(1));
    start = m.start + 1; //increment
}

Странно он находит только последнее вхождение, а не первое, второе и последнее. вывод вышеуказанного кода:

dog house trap
dog

Почему это? Я пытался привязать его к началу, добавив ^.*? к регулярному выражению, но это не помогло.

Ответы [ 4 ]

3 голосов
/ 15 февраля 2011

Вы можете сделать что-то вроде этого:

Pattern p = Pattern.compile("(cat|dog|bird)((?!cat|dog|bird).)*?trap");
Matcher m = p.matcher("cat dog house 131 bird 1341 house trap cat cat cat dog trap house dog house trap");
while (m.find()) {
  System.out.println(m.group(1) + " :: " + m.group(0));
}

, который производит:

bird :: bird 1341 house trap 
dog :: dog trap 
dog :: dog house trap

Краткое объяснение:

(cat|dog|bird)        # match one of: 'cat', 'dog' or 'bird'
(                     # start group 2
  (?!cat|dog|bird).   #  if none of 'cat', 'dog' or 'bird' are ahead, match any char (except line breaks)
)*?                   # end group 2 and reluctantly match it zero or more times
trap                  # match 'trap'

Вы могли бы добавьте trap в отрицательный прогноз, но квантификатор "неохотно" приведет к тому, что первое вхождение trap будет сопоставлено как конец.

2 голосов
/ 15 февраля 2011

Это потому, что ваше выражение говорит, что за животным не может следовать любое животное никогда.Вот почему подбирается только последнее «пойманное животное».

Это сложная проблема, которую нужно решить, поскольку в основном вы хотите сказать « с чем-то промежуточным, не соответствует bird|dog|cat ".

Лучшее решение, которое я могу придумать, - это (и это не красиво!)

import java.util.regex.*;

public class Test {

    public static void main(String[] args) {

        String pat = "(cat|dog|bird)([^bcd]|b(?!ird)|c(?!at)|d(?!og))*trap";

        String str = "cat dog house 131 bird 1341 house trap cat cat cat dog " +
                     "trap house dog house trap";

        Pattern p = Pattern.compile(pat);
        Matcher m = p.matcher(str);
        int start = 0;
        while (m.find(start)) {
            System.out.printf("Found trapped %s at %d%n", m.group(1), m.start());
            start = m.start() + 1;
        }
    }
}

Вывод:

Found trapped bird at 18
Found trapped dog at 51
Found trapped dog at 66

В основном это говорит,

  • cat|dog|bird, сопровождаемый
  • любым символом, кроме b, c и d, или
    • b (но не сопровождается ird), или
    • c (но не сопровождается at), или
    • d (ноне сопровождается og).
  • , за которым следует trap
0 голосов
/ 15 февраля 2011

Как заявляет aioobe, решить эту проблему бесполезно, и решить ее будет сложнее только с помощью RegEx, поскольку ваши требования станут более сложными.

Как насчет чего-то вроде (псевдокода) ...

str = "cat dog house 131 bird 1341 house trap cat cat cat dog trap house dog house trap";
arr = str.split(" "); //split on spaces
trapping = null;

for each item in arr {
  if (isTrap(item) && trapping != null) { 
    reportTrappedAnimal(trapping);
    trapping = null;     
  } else if (isAnimal(item)) { 
    trapping = item;
  }
}

Вы можете использовать регулярные выражения для реализации isAnimal() и isTrap(), но это может быть излишним или непрактичным в зависимости от ваших требований.

0 голосов
/ 15 февраля 2011

Я не могу редактировать, но в последней строке это должно быть start = m.start + 1;.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...