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

时间:2016-03-11 15:47:00

标签: regex lazy-evaluation

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

Regex101上的测试 我的测试字符串是:fn overwrite(&mut self, strt: &MyStruct) { // ^ self.field = strt.field.clone(); } fn main() { let mut s = MyStruct::new(); let s2 = MyStruct::new(); s.overwrite(&s2); // ^ println!("{:?}", s2); }

123456789D123456789匹配.{1,5}

12345匹配.{1,5}?

我对两场比赛都很好。

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

感谢您澄清这一点。

3 个答案:

答案 0 :(得分:8)

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

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

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

同样的情况会发生在5之前的位置。当引擎达到5时,它会尝试匹配5D,失败,尝试56D,失败,567D,失败,5678D - 再次失败,以及何时失败它试图匹配56789D - 宾果! - 找到了匹配。

这清楚地表明,在模式开头的懒惰量化的子模式将会贪婪地行动#34;默认情况下,也就是说,它与最短的子字符串不匹配。

以下是来自regex101.com的可视化:

enter image description here

现在,一个有趣的事实:模式末尾的.{1,5}?将始终匹配1个字符(如果有的话),因为要求至少匹配1,并且返回有效匹配就足够了。因此,如果您撰写D.{1,5}?,您将在D1中获得D6123456789D12345D678904

有趣的事实2 :在.NET中,您可以"问"正则表达式引擎在RightToLeft修饰符的帮助下从右到左分析字符串。然后,使用.{1,5}?D,您将获得9D,请参阅this demo

有趣的事实3 :在.NET中,如果(?<=(.{1,5}?))D作为输入传递,9会将123456789D捕获到组1中。这是因为lookbehind is implemented in .NET regex(.NET反转字符串以及lookbehind内部的模式,然后尝试匹配反向字符串上的单个模式)。在Java中,(?<=(.{1,5}))D(贪婪版本)将捕获9,因为它会尝试范围内的所有可能的固定宽度模式,从最短到最长,直到成功。

解决方案是:如果您知道需要1个字符后跟D,请使用

/.D/

答案 1 :(得分:0)

如果您的字符串包含数字后跟非数字,则最小值为{1,5}?永远是1(所以没有必要有范围。)我不认为懒惰的算子实际上正如我们对数值范围的思考。

如果您使第一个\ d +贪婪,如下所示,您将获得D之前的最小位数。

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

如果您使第一组数字变得懒惰,那么您将获得最大位数(5)

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

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

答案 2 :(得分:0)

你的正则表达式是

.{1,5}?D

匹配

123456789D123456789
    ------

但是你说你期望9D,因为使用&#34;非贪婪的量词&#34;。

无论如何,这个怎么样?

D.{1,5}?

匹配的结果是什么?

是的!正如你所期望的那样匹配

123456789D123456789
         --

那么,为什么?

好的,第一,我认为您需要了解通常正则表达式引擎将从输入字符串的左侧到右侧读取字符。考虑使用非贪婪量词的示例,一旦匹配引擎

123456789D123456789
    ------

它不会更进一步

123456789D123456789
     -----
123456789D123456789
      ----
...
123456789D123456789
        --

因为正则表达式引擎会尽可能少地评估文本,所以它也称为&#34;懒惰量词&#34;。

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

123456789D123456789
         ---
123456789D123456789
         ----
...
123456789D123456789
         ------

但是在第一场比赛中停止

123456789D123456789
         --