Regex 惰性量词{,}?不像我期望的那样工作

Regex 惰性量词{,}?不像我期望的那样工作,regex,lazy-evaluation,Regex,Lazy Evaluation,我对惰性量词有一个问题。或者很可能我误解了我应该如何使用它们 测试 我的测试字符串是:123456789D123456789 {1,5}匹配12345 {1,5}?匹配1 我对两场比赛都满意 {1,5}?D匹配56789D!!我希望它能匹配9D 感谢您澄清这一点。首先,请不要认为正则表达式中的贪婪和懒惰是获得最长/最短匹配的手段。“贪婪”和“懒惰”术语只适用于模式可以匹配的最右边的字符,对最左边的字符没有任何影响。当您使用惰性量词时,它将保证匹配子字符串的结尾将是第一个找到的,而不是最后一个找到

我对惰性量词有一个问题。或者很可能我误解了我应该如何使用它们

测试 我的测试字符串是:
123456789D123456789

{1,5}
匹配
12345

{1,5}?
匹配
1

我对两场比赛都满意

{1,5}?D
匹配
56789D
!!我希望它能匹配
9D


感谢您澄清这一点。

首先,请不要认为正则表达式中的贪婪和懒惰是获得最长/最短匹配的手段。“贪婪”和“懒惰”术语只适用于模式可以匹配的最右边的字符,对最左边的字符没有任何影响。当您使用惰性量词时,它将保证匹配子字符串的结尾将是第一个找到的,而不是最后一个找到的(将与贪婪量词一起返回)

正则表达式引擎从左到右分析字符串。因此,它搜索符合模式的第一个字符,然后,一旦找到匹配的子字符串,它将作为匹配返回

让我们看看它是如何用
{1,5}D
解析字符串的:找到
1
,并测试
D
。否
D
找到
1
后,正则表达式引擎展开惰性量词并匹配
12
并尝试匹配
D
。在
2
之后有
3
,同样,引擎将延迟点展开并执行5次。扩展到最大值后,它会看到有
12345
,下一个字符不是
D
。由于发动机达到最大限制量词值,匹配失败,测试下一个位置

同样的情况发生在
5
以下的位置。当发动机达到
5
时,它尝试匹配
5D
,失败,尝试
56D
,失败,
567D
,失败,
5678D
-再次失败,当它尝试匹配
56789D
-宾果!-找到了匹配项

这清楚地表明,在模式开始时,延迟量化的子模式在默认情况下将“贪婪地”运行,也就是说,它将不匹配最短的子字符串

以下是来自以下方面的可视化:

现在,这里有一个有趣的事实
{1,5}?
在模式的末尾总是匹配1个字符(如果有),因为要求至少匹配1个字符,并且返回一个有效的匹配就足够了。因此,如果您编写,您将在
1234567889D12345D678904
中获得
D1
D6

Fun Fact 2:在.NET中,您可以在
RightToLeft
修饰符的帮助下“要求”正则表达式引擎从右到左分析字符串。然后,使用
{1,5}?D
,您将获得
9D
,请参阅


Fun fact 3:在.NET中,
(?如果您有一个包含数字的字符串,后跟一个非数字,那么{1,5}的最小集将始终是1(因此不需要有范围)。我不认为懒惰运算符实际上是在数字范围上工作的

如果将第一个\d+设为贪婪,如下所示,则将得到d之前的最小位数

(\d+)(\d{1,5}d)
匹配第二组中的9D

如果将第一组数字设置为惰性,则将获得最大位数(5)

(\d+?)(\d{1,5}d)
匹配第二组的56789D

我认为这些正则表达式可能更符合您的需要。

您的正则表达式是

.{1,5}?D
火柴

123456789D123456789
    ------
但是你说你期望
9D
,因为使用了“非贪婪量词”

不管怎样,这个怎么样

D.{1,5}?
匹配的结果是什么

是的!正如你所预料的那样

123456789D123456789
         --
那么,为什么呢

好的,首先,我认为您需要了解,通常正则表达式引擎将从输入字符串的左侧到右侧读取字符

123456789D123456789
    ------
它将不会进一步讨论这个问题

123456789D123456789
     -----
123456789D123456789
      ----
...
123456789D123456789
        --
123456789D123456789
         ---
123456789D123456789
         ----
...
123456789D123456789
         ------
因为正则表达式引擎将尽可能少地计算文本,所以它也被称为“惰性量词”

它在我的正则表达式
D.{1,5}?
上也以同样的方式工作,这不应该进一步讨论

123456789D123456789
     -----
123456789D123456789
      ----
...
123456789D123456789
        --
123456789D123456789
         ---
123456789D123456789
         ----
...
123456789D123456789
         ------
但是在第一场比赛中停下来

123456789D123456789
         --

为什么在
{1,5}?D
中给定范围
{1,5}
时9D不匹配。为什么需要5(最大)个数字,为什么不需要1(最小)?@noob:因为“lazy”等于“最短可能匹配”。引擎从左到右运行,因此任何匹配都将具有最左边的起始字符。然而,在某些情况下,有一种方法可以获得
9D
,就像在.NET中一样(请参见有趣的事实2)。我的意思是
{1,5}
是贪婪的,它匹配
12345
{code>{1,5}?
是懒惰的,它匹配
1
。然后不应该
。{1,5}?D
也要懒惰,匹配
9D
?但它变得贪婪,匹配
56789D
。同样,你混淆了概念。贪婪和懒惰只适用于模式可以匹配的最右边的字符,与最左边的字符没有任何关系。我应该将此添加到我的答案开头。@noob我建议你玩一个我甚至不知道
{x,y}
量词可能会变懒,谢谢你问这个问题!