考虑以下 .NET 正则表达式:
^(REF)?(.{1,10})-(\d{12})-(\d+)$
它定义了四个组,我对它们感兴趣并将分别对其进行分析。
现在,考虑这个正则表达式的输入字符串:
参考文献03-123456789012-213
可以像这样匹配它:
(REF)(misc03)-(123456789012)-(213)
也可以这样匹配:
()(REFmisc03)-(123456789012)-(213)
是否记录了正则表达式引擎首选的方式,还是随机的?
考虑以下 .NET 正则表达式:
^(REF)?(.{1,10})-(\d{12})-(\d+)$
它定义了四个组,我对它们感兴趣并将分别对其进行分析。
现在,考虑这个正则表达式的输入字符串:
参考文献03-123456789012-213
可以像这样匹配它:
(REF)(misc03)-(123456789012)-(213)
也可以这样匹配:
()(REFmisc03)-(123456789012)-(213)
是否记录了正则表达式引擎首选的方式,还是随机的?
这不是随机的。这归结为正则表达式引擎如何解释量词和潜在的回溯。通过量词,我指的是?
in (REF)?
。根据 MSDN:
通常,量词是贪婪的。它们使正则表达式引擎匹配尽可能多的特定模式。附加 ? 量词的字符使它变得懒惰;它使正则表达式引擎匹配尽可能少的匹配项。
换句话说,?
是贪婪的,??
是懒惰的。两者都匹配零次或一次,但它们会对匹配的执行方式产生影响。
关于回溯,MSDN 提到:
正则表达式引擎尝试完全匹配可选或替代子表达式。当它前进到子表达式中的下一个语言元素并且匹配不成功时,正则表达式引擎可以放弃其成功匹配的一部分并返回先前保存的状态,以便将正则表达式作为一个整体与输入进行匹配细绳。这种返回到先前保存状态以查找匹配项的过程称为回溯。
另一个有用的资源可以在这里找到更多关于回溯的信息:Possessive Quantifiers。
要直接回答您的问题,我们可以比较这两种方法。
原始输入: REFmisc03-123456789012-213
的用法(REF)?
会将您的文本与 4 个组匹配(不包括具有整个匹配项的第一组),并且所有组都将成功匹配:
这匹配您的第一个可能的匹配场景(松散定义):
(REF)(misc03)-(123456789012)-(213)
只要该"misc..."
部分的长度为 1-10 个字符,则匹配将是相同的,所有 1-10 个字符都出现在第二组中。该REF
部分将始终在第一组中匹配。
新输入: REF-123456789012-213
该"misc..."
部分不存在。由于(REF)?
是可选的,而(.{1,10})
不是可选的,正则表达式引擎将使用"REF"
输入来满足模式的后(必需)部分,而忽略前(可选)部分。这将产生以下组值:
""
(空字符串,Success
属性 = false
)原始输入: REFmisc03-123456789012-213
通过使用(REF)??
, 并保持模式的其余部分相同,量词变得懒惰,这将返回 4 个具有这些值的组:
""
(空字符串,Success
属性 = false
)这与您的第二个可能的匹配方案相匹配:
()(REFmisc03)-(123456789012)-(213)
由于第一组是可选的,带有惰性量词,因此正则表达式引擎能够忽略它。由于"REFmisc03"
长度为 9 个字符,因此引擎会继续"REF"
使用,"misc03"
因为它们适合该(.{1,10})
组。
新输入: REF-123456789012-213
这与贪心模式的行为相似,并且适用相同的推理。
另一个新输入: REFmisc0345-123456789012-213
在此示例中,该"misc0345"
部分的长度为 8 个字符。尽管该模式使用了惰性量词,但它不能"REFmisc0345"
放入第二组,因为它超过了 10 个字符的限制。"REF"
正则表达式引擎将在第一组和第二组中回溯和匹配"misc0345"
: