Java正则表达式两个问号(??)

And*_*rew 6 regex

我知道 /?表示/是可选的.所以"玩具?" 将匹配玩具和玩具.我的理解是,如果我把它变得懒惰并使用"玩具??" 我将匹配玩具和玩具,并总是返回玩具.所以,快速测试:

private final static Pattern TEST_PATTERN = Pattern.compile("toys??", Pattern.CASE_INSENSITIVE);
public static void main(String[] args) {
    for(String arg : args) {
        Matcher m = TEST_PATTERN.matcher(arg);
        System.out.print("Arg: " + arg);
        boolean b = false;
        while (m.find()) {
            System.out.print(" {");
            for (int i=0; i<=m.groupCount(); ++i) {
                System.out.print("[" + m.group(i) + "]");
            }
            System.out.print("}");
        }
        System.out.println();
    }
}
Run Code Online (Sandbox Code Playgroud)

是的,它看起来像预期的那样工作

java -cp .. regextest.RegExTest toy toys
Arg: toy {[toy]}
Arg: toys {[toy]}
Run Code Online (Sandbox Code Playgroud)

现在,将正则表达式更改为"toys ?? 2",它仍然匹配toys2和toy2.在这两种情况下,它都会返回整个字符串而不删除s.搜索"玩具?2"和"玩具?? 2"之间是否有任何功能差异.

我问的原因是因为我找到了如下例子:

private final static Pattern TEST_PATTERN = Pattern.compile("</??tag(\\s+?.*?)??>", Pattern.CASE_INSENSITIVE);
Run Code Online (Sandbox Code Playgroud)

虽然我看到没有明显的理由使用?而不是?,我想也许原作者(我不认识的人)可能知道我不知道的东西,我期待后者.

nha*_*tdh 16

???贪婪是懒惰.

给定(pattern)??,它将首先测试空字符串,然后如果模式的其余部分不匹配,它将测试pattern.

相反,(pattern)?pattern首先测试,然后它将测试回溯上的空字符串.


现在,将正则表达式更改为"toys ?? 2",它仍然匹配toys2和toy2.在这两种情况下,它都会返回整个字符串而不删除s.搜索"玩具?2"和"玩具?? 2"之间是否有任何功能差异.

区别在于搜索顺序:

  • "toys?2"toys2然后搜索toy2
  • "toys??2"toy2然后搜索toys2

但是对于这两种模式的情况,无论输入字符串如何,结果都是相同的,因为必须匹配续集2(之后s?s??).


至于您找到的模式:

Pattern.compile("</??tag(\\s+?.*?)??>", Pattern.CASE_INSENSITIVE)
Run Code Online (Sandbox Code Playgroud)

两者??都可以更改为?不影响结果:

  • /t(in tag)相互排斥.你要么匹配其中一个.
  • >并且\s也是相互排斥的.至少1英寸\s+?对于这个结论很重要:否则结果可能不同.

这可能是作者的微观优化.他可能认为开放标记必须存在,而结束标记可能会被遗忘,而没有属性/随机空格的开放/关闭标记比具有某些标记的开放/关闭标记更常出现.

顺便说一句,引擎可能会遇到一些昂贵的回溯尝试,因为\\s+?.*?当输入<tag后面有很多空格而没有>任何附近.