我对贪婪的运算符在正面和负面的展望上感到困惑。
正向超前的脚本
foreach (<DATA>){
$_ = m/AAA.+(?=BBB)/g;
print "$&\n";
}
__DATA__
AAA 1121 BBB
AAA 443 CCC
AAA 4431 BBB
ABC 321 EACA
AAA 321 BBB
ACD 431 MAKN
AAA 751 ABC
它的输出
AAA 1121
AAA 4431
AAA 321
负前瞻
foreach (<DATA>){
$_ = m/AAA.+(?!BBB)/g;
print "$&\n";
}
它的输出
AAA 1121 BBB
AAA 443 CCC
AAA 4431 BBB
AAA 321 BBB
AAA 751 ABC
在执行
negative lookahed
时,不要考虑(?!BBB)
。因为我在(?!BBB)
之前使用贪婪运算符。在这种情况下,正向期望贪婪运算符会考虑使用(?=BBB)
。为什么给出不同的结果?我可以通过代码
$_ = m/AAA\s\d+(?!.+BBB)/g;
轻松实现OP。但是我不知道我的代码执行什么?
最佳答案
让我们考虑第一个示例:
AAA 1121 BBB
\_/\_______/^
| | |
| | +--- this (the empty string right there) satisfies (?!BBB)
| |
| +-------- matched by .+
|
+-------------- matched by AAA
这是因为贪婪的
.+
会消耗1121 BBB
,其中包括和BBB
。在使用完该行的其余部分之后,针对剩余的空字符串检查(?!BBB)
。而且此空字符串满足(?!BBB)
,因为它后面没有BBB
吗?负前瞻
该算法执行如下。
^
是当前位置(字符串中存在当前位置,并且模式中存在当前位置(种类))。AAA 1121 BBB AAA.+(?!BBB)
^ ^
AAA
AAA 1121 BBB AAA.+(?!BBB)
^ ^
.+
AAA 1121 BBB AAA.+(?!BBB)
^ ^
(?!BBB)
AAA 1121 BBB AAA.+(?!BBB)
^ ^
BBB
匹配=>成功!AAA 1121 BBB
\__________/
积极向前
现在,让我们看看为什么
AAA.+(?=BBB)
精确地产生匹配:AAA 1121 BBB AAA.+(?=BBB)
^ ^
AAA
AAA 1121 BBB AAA.+(?=BBB)
^ ^
.+
AAA 1121 BBB AAA.+(?=BBB)
^ ^
(?=BBB)
AAA 1121 BBB AAA.+(?=BBB)
^ ^
此位置没有
BBB
匹配=>回溯(通过.+
少消耗一个字符)(?=BBB)
AAA 1121 BBB AAA.+(?=BBB)
^ ^
此位置没有
BBB
匹配=>回溯(通过.+
少消耗一个字符)(?=BBB)
AAA 1121 BBB AAA.+(?=BBB)
^ ^
此位置没有
BBB
匹配=>回溯(通过.+
少消耗一个字符)(?=BBB)
AAA 1121 BBB AAA.+(?=BBB)
^ ^
BBB
匹配=>成功!AAA 1121 BBB
\_______/