Perl正则表达式如何否定部分

3

我有两个不相交的集合

D= d1| d2|...|dn

并且。
F=f1|f2|...|fn

目前我使用以下if语句来检查这两个正则表达式:

if (($text_to_search =~ $D) && ($text_to_search !~ $F))

如何否定F?是否可以使用负向先行断言来否定整个析取式或每个析取式?

应该像这样:

regexp = (d1)| (d2) | (d3)  ... (dn) | NOT (f1) | NOT (f2) | ... | Not (fn)

括号是必要的,用于否定模式,而不仅仅是第一个单字符,对吗?
编辑: 例如,D 是:a|b|c|d,F 是:1|2|3 现在行为应该像这样:
input: "abc" --> accepted
input: "a" --> accepted
input: "abc1" --> Not accepted
input: "2" --> NOT accepted
input: "a2bc1" --> Not accepted
(input: "xyz999" --> does not match - shouldn't be accepted)

F-disjunct应该被理解为“当在输入序列中看到此时,不匹配”。

1
你能展示一些样例输入和期望的行为吗? - Toto
你的意思不太清楚。你是想要与那个if语句相同的功能,但只有一个条件/表达式吗? - Qtax
就我个人而言,我认为问题已经很清晰了,但我不想回答。 - daxim
我想生成一个正则表达式,目前有两个,通过说 NOT regexp F 来实现。可以通过在一个表达式中表示以下析取不“允许”,或禁止每个单独的模式(如“NOT 1,NOT 2,NOT 3”)来实现。 - Tyzak
1个回答

2

是的,你可以使用负向先行断言。根据您的符号表示法,我们可以构建出这样一个结合了正则表达式的形状:

/(?!F)D/

不过还有些微妙之处。让我们来考虑一个简单的例子。

my $patternD = '^(\d\d\d\d | \w\w)$';
my $patternF = 'AA | 12';

正如您所看到的,patternD 匹配由 4 个数字或 2 个字母字符组成的字符串。PatternF 匹配 AA12。因此,以下片段将打印出我们期望的结果。
my $str = '1121';
print "patternD matches\n" if $str =~ /$patternD/x; # patternD matches
print "patternF matches\n" if $str =~ /$patternF/x; # patternF matches

现在,让我们采用一种简单的方法创建一个组合的正则表达式。
my $combined = "(?!($patternF))$patternD";
print "Combined regex matches\n" if $str =~ /$combined/x; # Combined regex matches?!

哎呀,我们这里有一个误报!(记住,我们的组合正则表达式应该只在正则表达式D匹配且F不匹配时匹配,但事实并非如此)。为什么呢?答案很简单。我们制作了组合正则表达式,以便如果D在某个位置匹配,则F只能从同一位置匹配。在这种情况下,D在$str的开头匹配(即\d\d\d\d),其中AA12都无法匹配。不过解决方法很简单。我们应该在F之前添加.*来给F一些灵活性。最终结果是:

 my $combined = "(?!.*($patternF))$patternD";

无论 D 匹配到哪里,F 都有机会在字符串中的任何地方匹配。
这个例子表明你想要实现的是可行的,但是你不能简单地混合两个正则表达式,你必须仔细检查最终结果。
希望对你有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接