这是一个很好的问题,我花了一段时间才明白自己懒惰的?? 量词的意义。
? - 可选(贪婪)量词
? 的用处很容易理解。如果你想同时找到http 和https,你可以使用这样的模式:
https?
此模式将匹配两个输入,因为它使 s 成为可选。
?? - 可选(惰性)量词
?? 更微妙。它通常与? 做同样的事情。当您询问以下问题时,它不会改变真/假结果:“此输入是否满足此正则表达式?” 相反,它与以下问题相关:“此输入的哪个部分与此正则表达式匹配,以及哪些部分属于哪些组?” 如果输入可以通过多种方式满足模式,引擎将根据? 与??(或*)决定如何对其进行分组对比*?,或+对比+?)。
假设您有一组要验证和解析的输入。这是一个(诚然愚蠢的)示例:
Input:
http123
https456
httpsomething
Expected result:
Pass/Fail Group 1 Group 2
Pass http 123
Pass https 456
Pass http something
你首先想到的是this:
^(http)([a-z\d]+)$
Pass/Fail Group 1 Group 2 Grouped correctly?
Pass http 123 Yes
Pass http s456 No
Pass http something Yes
它们都通过了,但你不能使用第二组结果,因为你只想要第 2 组中的456。
好吧,让我们try again。假设第 2 组可以是字母或数字,但不能同时是:
(https?)([a-z]+|\d+)
Pass/Fail Group 1 Group 2 Grouped correctly?
Pass http 123 Yes
Pass https 456 Yes
Pass https omething No
现在第二个输入没问题,但第三个分组错误,因为默认情况下? 是贪婪的(+ 也是,但? 排在第一位)。在确定s 是https? 还是[a-z]+|\d+ 的一部分时,如果结果是通过任一方式,正则表达式引擎将始终选择左边的那个。所以第 2 组输了s,因为第 1 组吃光了。
要解决此问题,您可以创建 one tiny change:
(https??)([a-z]+|\d+)$
Pass/Fail Group 1 Group 2 Grouped correctly?
Pass http 123 Yes
Pass https 456 Yes
Pass http something Yes
本质上,这意味着:“如果必须匹配 https,但看看当第 1 组只是 http 时这是否仍然通过。” 引擎意识到 s 可以作为[a-z]+|\d+ 的一部分工作,因此它更愿意将其放入第 2 组。