正则表达式量词中的混淆?JAVA

正则表达式量词中的混淆?JAVA,java,regex,Java,Regex,为什么我要为下面的正则表达式代码获取带有相关量词的输出ab Pattern p = Pattern.compile("abc*?"); Matcher m = p.matcher("abcfoo"); while(m.find()) System.out.println(m.group()); // ab 类似地,为什么要为下面的代码获取空索引 Pattern p = Pattern.compile(".*?"); Matcher m = p.m

为什么我要为下面的正则表达式代码获取带有相关量词的输出
ab

    Pattern p = Pattern.compile("abc*?");
    Matcher m = p.matcher("abcfoo");
    while(m.find())
      System.out.println(m.group()); // ab
类似地,为什么要为下面的代码获取空索引

   Pattern p = Pattern.compile(".*?");
   Matcher m = p.matcher("abcfoo");
   while(m.find())
     System.out.println(m.group());

*?
匹配零个或多个匹配,但尽可能少(顺便说一句,这通常称为“非贪婪”,而不是“不情愿”)。所以如果零匹配是可能的,那就是最佳匹配


你到底想要实现什么?也许你不需要非贪婪匹配。

除了康拉德·鲁道夫的答案:

abc*?
在任何情况下匹配
“ab”
,只有在必须匹配时才匹配
“c”
。由于
*?
之后没有任何内容,因此正则表达式引擎立即停止。如果你有:

abc*?f
然后它将匹配
“abcf”
,因为
“c”
必须匹配才能允许
“f”
也匹配。另一种说法是:

.*?
不匹配任何内容,因为此模式是100%可选的

.*?f

将再次匹配“abcf”。

将不情愿的量词作为正则表达式中的最后一项是没有意义的。一个不情愿的量词只能尽可能多地匹配,以实现整体匹配。这意味着在量词后面必须有一些东西来迫使它保持匹配


如果说有些东西可以被如此毫无意义地使用似乎有些奇怪的话,那可能是因为不情愿的量词是一个附加组件——这在“真正的”正则表达式中是不可能的。其他一些无意义用法的例子是带有量词的“量词”
{1}
,和
\b+
或任何其他零宽度断言(
^
$
,lookarounds等)。有些口味将后者视为语法错误;Java允许它,但当然只应用一次断言。

不情愿的量词使
*
匹配尽可能少的字符,如果回溯需要,只匹配更多字符

下面是一个使用正则表达式查找非空前缀的示例,该前缀也是字符串的后缀(无重叠)

第一个模式中的捕获组
\1
是贪婪的:它首先匹配所有内容,并在回溯时获取尽可能少的内容。因此,模式将找到最长的前缀/后缀匹配:

    System.out.println(
        "abracadabra".replaceAll("^(.+).*\\1$", "($1)")
    ); // prints "(abra)"
    System.out.println(
        "abracadabra".replaceAll("^(.+?).*\\1$", "($1)")
    ); // prints "(a)"
现在第二种模式中的
\1
是不情愿的;它首先不匹配任何内容,并在回溯时获取更多内容。因此,模式将找到最短的前缀/后缀匹配:

    System.out.println(
        "abracadabra".replaceAll("^(.+).*\\1$", "($1)")
    ); // prints "(abra)"
    System.out.println(
        "abracadabra".replaceAll("^(.+?).*\\1$", "($1)")
    ); // prints "(a)"
在您的例子中,
*?
可以匹配一个空字符串,并且不需要回溯和匹配更多的字符串,因为它足以匹配整个模式

另见

下面是有限重复中不情愿量词的另一个示例:

在这里,
x{3,5}
是贪婪的,并且将尽可能多地使用它

    System.out.println(
        "xxxxxxx".replaceAll("x{3,5}", "Y")
    ); // prints "Yxx"
    System.out.println(
        "xxxxxxx".replaceAll("x{3,5}?", "Y")
    ); // prints "YYx"
在这里,
x{3,5}?
是不情愿的,并且会尽可能少地使用

    System.out.println(
        "xxxxxxx".replaceAll("x{3,5}", "Y")
    ); // prints "Yxx"
    System.out.println(
        "xxxxxxx".replaceAll("x{3,5}?", "Y")
    ); // prints "YYx"

Java称之为“不情愿”。我认为“不情愿”是对他们最好的称呼,尽管“不贪婪”也很好。但“懒惰”(另一个最常见的形容词)在我看来是误导性的;他们实际上比贪婪或占有量词更努力。@Alan Moore:我同意,“懒惰”在CS中通常是其他意思(参见懒惰评估)。