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

A.D*_*.D. 4 regex lazy-evaluation

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

Regex101上 测试我的测试字符串是这样说的:123456789D123456789

.{1,5} 火柴 12345

.{1,5}? 火柴 1

我对两场比赛都很好.

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

谢谢你澄清这一点.

Wik*_*żew 8

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

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

让我们看看它如何解析字符串.{1,5}D:1找到并D进行测试.找不到D1,正则表达式引擎扩展了惰性量词并匹配12并尝试匹配D.有32,再次,发动机扩大了懒点,并做5次.在扩展到最大值后,它会看到存在12345而下一个字符不存在D.由于引擎达到最大限制量词值,匹配失败,测试下一个位置.

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

这清楚表明,模式开头的一个延迟量化的子模式默认情况下会"贪婪",也就是说,它与最短的子字符串不匹配.

以下是regex101.com的可视化:

在此输入图像描述

现在,这是一个有趣的事实:.{1,5}?在模式的最后总是匹配1个字符(如果有的话),因为要求至少匹配1,并且返回有效匹配就足够了.所以,如果你写的D.{1,5}?,你会得到D1D6123456789D12345D678904.

有趣的事实2:在.NET中,您可以"请求"正则表达式引擎在RightToLeft修改器的帮助下从右到左分析字符串.然后,.{1,5}?D你会得到9D,看看这个演示.

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

一个解决方案是:如果你知道你需要1个字符D,只需使用

/.D/
Run Code Online (Sandbox Code Playgroud)