我无法理解负前瞻正则表达式的细节。在阅读了Regex lookahead、lookbehind 和 atomic groups之后,当我发现这个描述时,我以为我对负前瞻有了一个很好的总结:
(?!REGEX_1)REGEX_2
仅当
REGEX_1
不匹配时才匹配;检查后REGEX_1
,搜索REGEX_2
从同一位置开始。
希望我理解算法,我编造了一个两句测试侮辱;我想找到没有某个词的句子。具体来说...
侮辱: 'Yomama很丑。而且,她闻起来像一条湿狗。
要求:
- 测试 1:返回一个没有“丑陋”的句子。
- 测试 2:返回一个没有“looks”的句子。
- 测试 3:返回一个没有“气味”的句子。
我将测试词分配给$arg
,并用于(?:(?![A-Z].*?$arg.*?\.))([A-Z].*?\.)
执行测试。
(?![A-Z].*?$arg.*?\.)
是否定前瞻来拒绝带有测试词的句子([A-Z].*?\.)
至少匹配一个句子。
关键部分似乎在于理解正则表达式引擎在处理负前瞻后开始匹配的位置。
预期结果:
- 测试 1 ($arg = "ugly"):“而且,她闻起来像一条湿狗。”
- 测试 2 ($arg = "looks"): "Yomama 很丑。"
- 测试 3 ($arg = "smells"): "Yomama 很丑。"
实际结果:
- 测试 1 ($arg = "ugly"):“而且,她闻起来像一条湿狗。” (成功)
- 测试 2 ($arg = "looks"): "Yomama 很丑。" (成功)
- 测试 3 ($arg = "smells"):失败,不匹配
一开始我以为Test 3失败([A-Z].*?\.)
是因为太贪心,两个句子都匹配;但是,(?:(?![A-Z].*?$arg.*?\.))([A-Z][^\.]*?\.)
也没有用。接下来我想知道python负前瞻实现是否有问题,但perl给了我完全相同的结果。
最后我找到了解决方案,我不得不.*?
通过使用来拒绝我的部分表达式中的句点[^\.]*?
;所以这个正则表达式有效:(?:(?![A-Z][^\.]*?$arg[^\.]*?\.))([A-Z][^\.]*?\.)
问题
但是,我还有另一个担心;“Yomama很丑。” 里面没有“气味”。那么,如果.*?
应该是非贪婪匹配,为什么我不能用 完成测试 3 (?:(?![A-Z].*?$arg.*?\.))([A-Z].*?\.)
?
编辑
鉴于@bvr 对使用的极好建议-Mre=debug
,我会在下班后考虑更多。看来赛斯的描述在这一点上是准确的。到目前为止,我学到的是负前瞻表达式将尽可能匹配,即使我.*?
在 NLA 中放置了非贪婪运算符。
Python 实现
import re
def test_re(arg, INSULTSTR):
mm = re.search(r'''
(?: # No grouping
(?![A-Z].*?%s.*?\.)) # Negative zero-width
# assertion: arg, followed by a period
([A-Z].*?\.) # Match a capital letter followed by a period
''' % arg, INSULTSTR, re.VERBOSE)
if mm is not None:
print "neg-lookahead(%s) MATCHED: '%s'" % (arg, mm.group(1))
else:
print "Unable to match: neg-lookahead(%s) in '%s'" % (arg, INSULTSTR)
INSULT = 'Yomama is ugly. And, she smells like a wet dog.'
test_re('ugly', INSULT)
test_re('looks', INSULT)
test_re('smells', INSULT)
Perl 实现
#!/usr/bin/perl
sub test_re {
$arg = $_[0];
$INSULTSTR = $_[1];
$INSULTSTR =~ /(?:(?![A-Z].*?$arg.*?\.))([A-Z].*?\.)/;
if ($1) {
print "neg-lookahead($arg) MATCHED: '$1'\n";
} else {
print "Unable to match: neg-lookahead($arg) in '$INSULTSTR'\n";
}
}
$INSULT = 'Yomama is ugly. And, she smells like a wet dog.';
test_re('ugly', $INSULT);
test_re('looks', $INSULT);
test_re('smells', $INSULT);
输出
neg-lookahead(ugly) MATCHED: 'And, she smells like a wet dog.'
neg-lookahead(looks) MATCHED: 'Yomama is ugly.'
Unable to match: neg-lookahead(smells) in 'Yomama is ugly. And, she smells like a wet dog.'