Java: template behaves differently in scanner
Affects strange regex matching behavior in Java. The first output command prints true
as expected, but when the same line is packed into Scanner
, the output is false
. What am I doing wrong?
public static void main(String[] args) {
Pattern p = Pattern.compile(" *\\[");
System.out.println(p.asPredicate().test("[]")); //true
Scanner s = new Scanner("[]");
System.out.println(s.hasNext(" *\\[")); //false
}
source to share
From public boolean hasNext(String pattern)
documentation :
Returns true if the next token matches the pattern built from the specified string.
Here the next token is []
not easy [
(since the delimiter is one or more spaces), but the pattern " *\\["
does not exactly match that token ( ]
does not match), so you are informed about it by the result false
.
If you want to check if a token starts with [
, you can add .*
at the end of your template to match the remainder of the token. You can also remove *
, since the space is the default delimiter, so it cannot be part of the token.
When
Pattern p = Pattern.compile(" *\\[");
System.out.println(p.asPredicate().test("a[]")); //true
If you look at the code asPredicate
, you can see that it is implemented as:
public Predicate<String> asPredicate() {
return s -> matcher(s).find();
}
find()
the method does not check if the whole string matches the pattern, but tries to find even the part of it that matches the pattern. Since it []
contains zero or more spaces followed by [
you, you see the result true
.
source to share
According to the Predicate.test
description from the Javadoc:
... true if the input argument matches the predicate, otherwise false
Something that is not explicitly written in the Javadoc, but implies that the method test(T t)
does not match the method String.matches(String)
where the starting and ending anchors are implicit. test
method, on the other hand, does not match the full string and you will need to use anchors in your regex to make it behave like methods String.matches
or Scanner.hasNext(Pattern )
.
The following code will give a consistent result false
from both calls
final String input = "[]";
final String re = "^ *\\[$"; // note use of anchors in the regex
final Pattern p = Pattern.compile(re);
System.out.println(p.asPredicate().test(input)); // false
Scanner s = new Scanner(input);
System.out.println(s.hasNext(p)); //false
s.close();
source to share