我有一个字符串$s1 = "a_b";,我想匹配这个字符串,但只捕获字母.我试图使用前瞻:
if($s1 =~ /([a-z])(?=_)([a-z])/){print "Captured: $1, $2\n";}
Run Code Online (Sandbox Code Playgroud)
但这似乎与我的字符串不匹配.我用(?:_)相反的方法解决了原来的问题,但我很好奇为什么我的原始尝试不起作用?根据我的理解,先行匹配但不捕获,所以我做错了什么?
前瞻查找下一个直接位置,如果发生了真正的断言,它会回溯到上一个匹配 - 之后a- 继续匹配.你的正则表达式只有当你带来一个_积极的前瞻性时才会起作用([a-z])(?=_)_([a-z])
您甚至不需要(非)捕获组代替:
if ($s1 =~ /([a-z])_([a-z])/) { print "Captured: $1, $2\n"; }
Run Code Online (Sandbox Code Playgroud)
回复@Borodin的评论
我认为向后移动与通过调试整个事物(Perl调试模式)更容易识别的回溯相同:
Matching REx "a(?=_)_b" against "a_b"
.
.
.
0 <> <a_b> | 0| 1:EXACT <a>(3)
1 <a> <_b> | 0| 3:IFMATCH[0](9)
1 <a> <_b> | 1| 5:EXACT <_>(7)
2 <a_> <b> | 1| 7:SUCCEED(0)
| 1| subpattern success...
1 <a> <_b> | 0| 9:EXACT <_b>(11)
3 <a_b> <> | 0| 11:END(0)
Match successful!
Run Code Online (Sandbox Code Playgroud)
如上所述,调试输出显示在结果的第四行(当第3步发生时)引擎消耗字符a_(在处于先行断言中)然后我们看到在成功断言正向前导后发生回溯,引擎跳过整个子模式以相反的方式,从正确的位置开始a.
在第5行,引擎只消耗了一个字符:a.Regex101调试器:
我如何解释这个回溯在这个插图中更清楚(感谢@JDB,我借用了他的表现风格)
a(?=_)_b
*
|\
| \
| : a (match)
| * (?=_)
| |?
| | ?
| |? ?
| | ? ?
| | ? ?
| | : _ (match)
| | ^ SUBPATTERN SUCCESS (OP_ASSERT :=> MATCH_MATCH)
| * _b
| |\
| | \
| | : _ (match)
| | : b (match)
| | /
| |/
| /
|/
MATCHED
Run Code Online (Sandbox Code Playgroud)
我的意思是,如果前瞻断言成功 - 因为输入字符串的部分被提取 - 它向上返回(返回到前一个匹配偏移 - (eptr(指向主题的指针)没有改变但偏移是)并且在重置消耗的字符时它尝试从那里继续匹配,我称之为回溯.下面是引擎使用的步骤的直观表示Regexp::Debugger
因此,我认为这是一个回溯或一种,但如果我对所有这些说错了,那么我会欣赏张开双臂的任何回收.