我有一个字符串$s1 = "a_b";
,我希望匹配此字符串,但只捕获字母。我试图使用前瞻:
if($s1 =~ /([a-z])(?=_)([a-z])/){print "Captured: $1, $2\n";}
但这似乎与我的字符串不匹配。我通过使用(?:_)
来解决原始问题,但我很好奇为什么我的原始尝试不起作用?根据我的理解,前瞻性匹配但不捕获,所以我做错了什么?
答案 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调试器:
我如何解释这个回溯在这个例子中更清楚(感谢@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
所以我认为这是一个回溯或种,但如果我对所有这些说错了,那么我会赞赏任何开放式的回收。