在Perl中否定正则表达式

时间:2013-07-24 13:01:28

标签: regex perl negate

我正在将文本文件拆分成块,以便使用正则表达式提取包含某一行的块。 文本文件如下所示:

[Term]  
id: id1  
name: name1  
xref: type1:aab  
xref: type2:cdc  

[Term]  
id: id2  
name: name2  
xref: type1:aba  
xref: type3:fee 

几天前有人通过向我展示如何提取包含某个正则表达式的块(例如“xref:type3”)来帮助我:

while (<MYFILE>) {
  BEGIN { $/ = q|| }
    my @lines = split /\n/;
    for my $line ( @lines ) {
        if ( $line =~ m/xref:\s*type3/ ) {
            printf NEWFILE qq|%s|, $_;
            last;
        }
    }
}

现在我想在新文件中写入不包含“xref:type3”的所有块。我试图通过简单地否定正则表达式

来做到这一点
if ( $line !~ m/xref:\s*type3/ )

或者通过使用

否定if语句
unless ( $line =~ m/xref:\s*type3/ )

不幸的是它不起作用 - 输出文件与原始文件相同。我有什么想法吗?

3 个答案:

答案 0 :(得分:3)

你有:

对于每一行,如果此行与模式不匹配,请打印此块。

但你想要:

对于每一行,如果块中没有其他行与模式匹配,则打印此行。

因此,在检查块中的每一行之前(或直到找到匹配的行之前的所有行),都无法开始打印块。

local $/ = q||;
while (<MYFILE>) {
    my @lines = split /\n/;

    my $skip = 0;
    for my $line ( @lines ) {
        if ( $line =~ m/^xref:\s*type3/ ) {
            $skip = 1; 
            last;
        }
    }

    if (!$skip) {
        for my $line ( @lines ) {
            print NEWFILE $line;
        }
    }
}

但是没有必要分成几行。我们可以立即检查并打印整个块。

local $/ = q||;
while (<MYFILE>) {
    print NEWFILE $_ if !/^xref:\s*type3/m;
}

(请注意/m使^与任意行的开头匹配。)

答案 1 :(得分:1)

不要逐行处理记录。使用段落模式:

{   local $/ = q();
    while (<MYFILE>) {
        if (! /xref:\s*type3/ ) {
            printf NEWFILE qq|%s|, $_;
            last;
        }
}

答案 2 :(得分:1)

问题在于您使用unless !~,其解释为$line NOT 匹配不执行此操作。 (双重否定)

unless块与正常模式匹配运算符=~一起使用时,您的代码运行正常,即我将第一个块视为输出,因为它不包含type3。

LOOP:
while (<$MYFILE>) {
  BEGIN { $/ = q|| }
    my @lines = split /\n/;
    for my $line ( @lines ) {
        unless ( $line =~ m/xref:\s*type3/ ) {
            printf qq|%s|, $_;
            last LOOP;
        }
  }
}

# prints
# [Term]
# id: id1
# name: name1
# xref: type1:aab
# xref: type2:cdc
相关问题