20

I have the following Java code:

Pattern pat = Pattern.compile("(?<!function )\\w+");
Matcher mat = pat.matcher("function example");
System.out.println(mat.find());

Why does mat.find() return true? I used negative lookbehind and example is preceded by function. Shouldn't it be discarded?

assylias
  • 321,522
  • 82
  • 660
  • 783
Sorin
  • 908
  • 2
  • 8
  • 19

3 Answers3

36

See what it matches:

public static void main(String[] args) throws Exception {
    Pattern pat = Pattern.compile("(?<!function )\\w+");
    Matcher mat = pat.matcher("function example");
    while (mat.find()) {
        System.out.println(mat.group());
    }
}

Output:

function
xample

So first it finds function, which isn't preceded by "function". Then it finds xample which is preceded by function e and therefore not "function".

Presumably you want the pattern to match the whole text, not just find matches in the text.

You can either do this with Matcher.matches() or you can change the pattern to add start and end anchors:

^(?<!function )\\w+$

I prefer the second approach as it means that the pattern itself defines its match region rather then the region being defined by its usage. That's just a matter of preference however.

Boris the Spider
  • 59,842
  • 6
  • 106
  • 166
  • 1
    I don't understand the solution adding the starting string anchor. Isn't that always going to return true, since the check is done at the beginning of the string and there's noway "function " is going to precede the starting string anchor? While `\\w` cannot possibly match the space, so nothing is found? It also doesn't find a match on "method example". – Scratte Feb 22 '21 at 13:09
  • There’s also an end anchor @Scratte. – Boris the Spider Feb 22 '21 at 21:52
  • Yes. There is. How does that change anything? [It will only match a string of word characters. It doesn't check for function in the string itself](https://regex101.com/r/xOfomX/1) – Scratte Feb 22 '21 at 22:08
1

Your string has the word "function" that matches \w+, and is not preceded by "function ".

1

Notice two things here:

  • You're using find() which returns true for a sub-string match as well.

  • Because of the above, "function" matches as it is not preceded by "function".
    The whole string would have never matched because your regex didn't include spaces.

Use Mathcher#matches() or ^ and $ anchors with a negative lookahead instead:

Pattern pat = Pattern.compile("^(?!function)[\\w\\s]+$"); // added \s for whitespaces
Matcher mat = pat.matcher("function example");

System.out.println(mat.find()); // false
Ravi K Thapliyal
  • 51,095
  • 9
  • 76
  • 89