我正在将文本文件拆分成块,以便使用正则表达式提取不包含某一行的块。 文本文件如下所示:
[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/ )
不幸的是它不起作用 - 输出文件与原始文件相同。我有什么想法吗?
答案 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