贪婪运算符的结果在正面和负面前瞻中有所不同?
Greedy operator result is differ in positive and negative lookahead?
我对正面和负面前瞻的贪婪运算符感到困惑。
用于正面前瞻
的脚本
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
?
否定前瞻
算法执行如下。 ^
是 当前位置 (字符串中有一个当前位置,模式中有一个当前位置 (kind of)).
初始状态:
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
\_______/
在你的两种情况下它的工作方式没有区别,并且.+
在你的两种情况下都是贪婪的。
在匹配AAA.+(?=BBB)
和AAA 1121 BBB
时,最多.+
可以匹配AAA
之后的<spc>1121<spc>
。任何更长的时间都会导致 (?=BBB)
失败。
在匹配AAA.+(?!BBB)
和AAA 1121 BBB
时,最多.+
可以匹配AAA
之后的<spc>1121<spc>BBB
。作为字符串的其余部分,它不可能再匹配任何内容。
请注意,字符串末尾后没有 BBB
,因此 (?!BBB)
匹配字符串末尾。
(?:(?!STRING).)*
之于 STRING
正如 [^CHAR]*
之于 CHAR
.
我会选择
say if /^(AAA\s+\S+)\s+(?:(?!BBB)\s)*\z/;
再三考虑,我会选择
my @F = split;
say "$F[0] $F[1]" if $F[0] eq 'AAA' && $F[2] ne 'BBB';
我对正面和负面前瞻的贪婪运算符感到困惑。
用于正面前瞻
的脚本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
?
否定前瞻
算法执行如下。 ^
是 当前位置 (字符串中有一个当前位置,模式中有一个当前位置 (kind of)).
初始状态:
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 \_______/
在你的两种情况下它的工作方式没有区别,并且.+
在你的两种情况下都是贪婪的。
在匹配AAA.+(?=BBB)
和AAA 1121 BBB
时,最多.+
可以匹配AAA
之后的<spc>1121<spc>
。任何更长的时间都会导致 (?=BBB)
失败。
在匹配AAA.+(?!BBB)
和AAA 1121 BBB
时,最多.+
可以匹配AAA
之后的<spc>1121<spc>BBB
。作为字符串的其余部分,它不可能再匹配任何内容。
请注意,字符串末尾后没有 BBB
,因此 (?!BBB)
匹配字符串末尾。
(?:(?!STRING).)*
之于 STRING
正如 [^CHAR]*
之于 CHAR
.
我会选择
say if /^(AAA\s+\S+)\s+(?:(?!BBB)\s)*\z/;
再三考虑,我会选择
my @F = split;
say "$F[0] $F[1]" if $F[0] eq 'AAA' && $F[2] ne 'BBB';