在正则表达式中间的前瞻不匹配

ham*_*doo 2 regex perl

我有一个字符串$s1 = "a_b";,我想匹配这个字符串,但只捕获字母.我试图使用前瞻:

if($s1 =~ /([a-z])(?=_)([a-z])/){print "Captured: $1, $2\n";}
Run Code Online (Sandbox Code Playgroud)

但这似乎与我的字符串不匹配.我用(?:_)相反的方法解决了原来的问题,但我很好奇为什么我的原始尝试不起作用?根据我的理解,先行匹配但不捕获,所以我做错了什么?

rev*_*evo 6

前瞻查找下一个直接位置,如果发生了真正的断言,它会回溯到上一个匹配 - 之后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

在此输入图像描述

因此,我认为这是一个回溯或一种,但如果我对所有这些说错了,那么我会欣赏张开双臂的任何回收.