我知道 /?表示/是可选的。那么“玩具?”将匹配玩具和玩具。我的理解是,如果我变得懒惰并使用“玩具?”我将玩具与玩具都匹配,并且总是返回玩具。因此,快速测试:

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”,它仍然匹配toy2和toy2。在这两种情况下,它都返回完整的字符串,而不删除。搜索“ toys?2”和“ toys ?? 2”之间在功能上有什么区别。

我问的原因是因为我找到了一个类似以下示例:

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


尽管我没有明显的理由使用??而不是?,我认为也许是原作者(我不认识的作者)可能会知道我不知道的东西,我希望以后会知道。

最佳答案

??是懒惰的,而?是贪婪的。

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

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




现在,将正则表达式更改为“ toys ?? 2”,它仍然匹配toy2和toy2。在这两种情况下,它都返回完整的字符串,而不删除。搜索“ toys?2”和“ toys ?? 2”之间在功能上有什么区别。


区别在于搜索顺序:


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


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



至于您发现的模式:

Pattern.compile("</??tag(\\s+?.*?)??>", Pattern.CASE_INSENSITIVE)


可以将两个??都更改为?,而不会影响结果:


/t(在tag中)是互斥的。您可以彼此匹配。
>\s也是互斥的。 \s+?中的至少1对于此结论很重要:否则结果可能会有所不同。


作者可能对此进行了微优化。他可能认为打开标签必须存在,而关闭标签可能会被遗忘,并且没有属性/随机空间的打开/关闭标签比带有某些标签的打开/关闭标签的出现频率更高。

顺便说一句,当输入有\\s+?.*?且后面有很多空格且附近没有<tag时,由于>,引擎可能会进行一些昂贵的回溯尝试。

07-23 21:56