Java:在Scanner中,Pattern的行为不同

3

在Java中遇到了正则表达式匹配的奇怪行为。第一个输出命令按预期打印true,但当相同的字符串被打包到Scanner中时,输出为false。我做错了什么?

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
}

尝试使用s.hasNext(p) - logi-kal
@horcrux 来自javadoc的内容:调用这种形式为<tt>hasNext(pattern)</tt>的方法将与调用<tt>hasNext(Pattern.compile(pattern))</tt>完全相同。 - SpaceTrucker
1
@SpaceTrucker 你说得对。所以重点是 Pattern.compile(myRegex).asPredicate().test(myString)myString 中搜索 myRegex 的出现,而 new Scanner(myString).hasNext(myRegex) 则检查整个 myString 的内容是否与 myRegex 匹配。 - logi-kal
2个回答

6

根据文档中的说明,public boolean hasNext(String pattern)方法返回一个布尔值,表示下一个标记是否与指定字符串构建的模式匹配。

在这里,下一个标记是[],而不仅仅是[(因为分隔符是一个或多个空格)。但是" *\\["模式并没有完全匹配该标记(未匹配]),因此结果为false

如果您想检查标记是否以[开头,可以在模式末尾添加.*以使其匹配其余标记。您还可以删除*,因为空格是默认分隔符,因此它不能成为标记的一部分。


如果出现

Pattern p = Pattern.compile(" *\\[");
System.out.println(p.asPredicate().test("a[]")); //true

如果你查看asPredicate的代码,你会发现它是这样实现的:
public Predicate<String> asPredicate() {
    return s -> matcher(s).find();
}

find()方法并不检查整个字符串是否与模式匹配,而是试图找到与模式匹配的一部分。由于[]包含零个或多个空格,后跟[,因此您会看到结果为true


我明白了。有没有可能检查令牌的开头,或者我应该在每个正则表达式的末尾添加.* - Viacheslav Kroilov
这里最简单的方法是在末尾添加.*。但是根据您想要实现的目标,也许最好避免使用Scanner,直接使用Pattern会更好?不知道您真正想要实现什么,很难说。 - Pshemo
我正在解析一个包含类似JSON的数组的字符串,所以我需要直接访问字符并且能够轻松地解析整数或浮点数。在这种情况下,有没有Scanner的替代方案?使用JSON解析器不是一个选择,这个情况无法通用处理。 - Viacheslav Kroilov
@ViacheslavKroilov,没有实际数据和期望结果,我无法提供更多信息。由于此问题已经有几个答案涉及当前描述的问题,如果对其进行修改,将使发布的答案失效,因此如果您希望就您的具体情况提问,请考虑创建单独的问题。 - Pshemo

0
根据Javadoc中Predicate.test的描述:
如果输入参数与谓词匹配,则为true,否则为false。
虽然在Javadoc中没有明确写出来,但是暗示着test(T t)方法不像String.matches(String)方法那样匹配,其中开始和结束锚点是隐含的。另一方面,test方法不会完全匹配字符串,您需要在正则表达式中使用锚点才能使其像String.matchesScanner.hasNext(Pattern )方法一样运行。
以下代码将从两个调用中都得到一致的false结果。
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();      

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接