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

时间:2014-01-22 16:51:47

标签: 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();
    }
}

是的,看起来它按预期工作

java -cp .. regextest.RegExTest toy toys
Arg: toy {[toy]}
Arg: toys {[toy]}

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

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

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

虽然我看不出使用的明显理由?而不是?,我想也许原作者(我不认识的人)可能知道我不知道的事情,我期待后者。

1 个答案:

答案 0 :(得分: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)

??可以更改为?而不会影响结果:

  • /ttag互斥。你要么匹配其中一个。
  • >\s互斥\s+?中的至少1对此结论很重要:否则结果可能不同。

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

顺便说一下,当输入\\s+?.*?后面有很多空格而<tag靠近任何地方时,引擎可能会因>而进行一些昂贵的回溯尝试。

相关问题