为了更好地理解,让我们应用三个表达式加上一个捕获组并分析每个行为。
()
捕获组- 括号内的正则表达式必须匹配并且匹配创建一个捕获组
(?:)
非捕获组- 括号内的正则表达式必须匹配但不创建捕获组
(?=)
积极的前瞻- 断言正则表达式必须匹配
(?!)
负前瞻- 断言不可能匹配正则表达式
让我们申请q(u)i
退出。匹配q并且捕获组匹配u。获取捕获组内的匹配并创建捕获组。所以引擎继续。并将匹配i。最后一次匹配尝试是成功的。qui匹配并创建了一个带有u的捕获组。
q
u
i
i
让我们申请q(?:u)i
退出。同样,匹配q并且非捕获组匹配u。来自非捕获组的匹配被取走,但不创建捕获组。所以引擎继续。并将匹配i。最后一次匹配尝试是成功的。qui匹配。
q
u
i
i
让我们申请q(?=u)i
退出。前瞻是肯定的,后面跟着另一个令牌。同样,匹配q并匹配u。但是来自前瞻的匹配必须被丢弃,因此引擎从字符串中退回到u。鉴于前瞻成功,引擎继续运行。但不能匹配u。所以这个匹配尝试失败了。
q
u
i
i
i
让我们申请q(?=u)u
退出。前瞻是肯定的,后面跟着另一个令牌。同样,匹配q并匹配u。但是来自前瞻的匹配必须被丢弃,因此引擎从字符串中退回到u。鉴于前瞻成功,引擎继续运行。并且会匹配u。所以这个匹配尝试是成功的。qu匹配。
q
u
u
u
u
让我们申请q(?!i)u
退出。即使在这种情况下,前瞻也是肯定的(因为不匹配),并且后面跟着另一个令牌。同样,匹配q并且不匹配u。来自前瞻的匹配必须被丢弃,因此引擎从字符串中退回到u。鉴于前瞻成功,引擎继续运行。并且会匹配u。所以这个匹配尝试是成功的。qu匹配。
i
q
i
u
u
u
因此,总而言之,前瞻组和非捕获组之间的真正区别在于您是否只想测试存在或测试并保存匹配。
但是捕获组很昂贵,因此请明智地使用它。