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

时间:2016-09-04 21:07:23

标签: regex perl

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

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

但这似乎与我的字符串不匹配。我通过使用(?:_)来解决原始问题,但我很好奇为什么我的原始尝试不起作用?根据我的理解,前瞻性匹配但不捕获,所以我做错了什么?

1 个答案:

答案 0 :(得分:5)

前瞻查找下一个直接位置,如果发生了真正的断言,它会回溯到上一个匹配 - 在a之后 - 继续匹配。只有当您在正面预测_

旁边带([a-z])(?=_)_([a-z])时,您的正则表达式才有效

你甚至不需要(非)捕捉群体代替:

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

修改

回复@ 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!

如上所述,调试输出显示在第四行结果(当发生第3步时)引擎消耗字符a_(当处于先行断言时)然后我们看到在成功断言正向前导后发生了回溯,引擎以相反的方式跳过整个子图案,并从a之后的位置开始。

在第5行,引擎只消耗了一个字符:a。 Regex101调试器:

enter image description here

我如何解释这个回溯在这个例子中更清楚(感谢@JDB,我借了他的style of representation

a(?=_)_b
*
|\
| \
|  : a (match)
|  * (?=_)
|  |↖
|  | ↖
|  |↘ ↖
|  | ↘ ↖
|  |  ↘ ↖
|  |   : _ (match)
|  |     ^ SUBPATTERN SUCCESS (OP_ASSERT :=> MATCH_MATCH)
|  * _b
|  |\
|  | \
|  |  : _ (match)
|  |  : b (match)
|  | /
|  |/
| /
|/
MATCHED

我的意思是,如果前瞻断言成功 - 因为输入字符串的部分被提取 - 它会向上返回(返回上一个匹配偏移 - (eptr(指向主题的指针)is not changed but offset is并且在重置消耗的字符时,它尝试从那里继续匹配,我将其称为回溯。下面是引擎使用Regexp::Debugger

所采取的步骤的直观表示。

enter image description here

所以我认为这是一个回溯或,但如果我对所有这些说错了,那么我会赞赏任何开放式的回收。