我正在匹配一个模式并使用$.
我需要在特定模式之前和特定模式之后打印匹配的行,例如:
line1
line2
line3
line4
line5
我的模式与line3
匹配后,我想打印line2
和line4
。
如何在Perl中进行模式匹配?任何人都可以帮助我吗?
提前致谢
塞特希
答案 0 :(得分:3)
您想要通常称为上下文的内容。获取上下文的最简单方法是使用变量自己维护它:
#!/usr/bin/perl
use strict;
use warnings;
my $old;
while (my $line = <DATA>) {
if ($line =~ /line3/) {
print "$old$line", scalar <DATA>;
last;
}
$old = $line;
}
__DATA__
line1
line2
line3
line4
line5
如果您需要多行上下文,最好使用数组:
#!/usr/bin/perl
use strict;
use warnings;
my $context = shift || 3;
if ($context < 0) {
$context = 0;
}
my @old;
while (my $line = <DATA>) {
if ($line =~ /line6/) {
print @old, $line;
for (1 .. $context) {
print scalar <DATA>;
}
last;
}
push @old, $line;
#remove a line if we have more than we need
if (@old > $context) {
shift @old;
}
}
__DATA__
line1
line2
line3
line4
line5
line6
line7
line8
line9
答案 1 :(得分:3)
将整个文件放在标量中,编写模式,以便捕获line3
之前和之后的行。 /m
modifier特别有用:
将字符串视为多行。也就是说,更改
^
和$
以匹配字符串的开头或结尾,以匹配字符串中任何位置的任何行的开头或结尾。
下面的模式使用/x
修饰符,它允许我们添加空格,使它们看起来像是匹配的。
例如:
#! /usr/bin/perl
my $data = do { local $/; <DATA> };
my $pattern = qr/ ^(.+\n)
^line3\n
^(.+\n)
/mx;
if ($data =~ /$pattern/) {
print $1, $2;
}
else {
print "no match\n";
}
__DATA__
line1
line2
line3
line4
line5
输出:
line2 line4
请记住$
是一个断言:它不会消耗任何字符,因此您必须将换行符与文字\n
模式匹配。
另请注意,上述模式缺乏一般性。它适用于中间某处的某条线,但如果您将line3
更改为line1
或line5
,则会失败。
对于line1
案例,您可以使用?
量词使前一行可选:
my $pattern = qr/ ^(.+\n)?
^line1\n
^(.+\n)
/mx;
正如预期的那样,这会产生
的输出line2
但是对line5
案例
my $pattern = qr/ ^(.+\n)?
^line5\n
^(.+\n)?
/mx;
给出
no match
这是因为在文件中的最后一个换行符(line5
后面的那个换行符)之后,^
无处可匹配,但将模式更改为
my $pattern = qr/ ^(.+\n)?
^line5\n
(^.+\n)?
/mx;
输出
line4
我们可能会停在这里,但模式中的不对称是令人不快的。为什么一个案件而不是另一个案件呢?使用line1
,^
匹配$data
的开头,然后匹配(.+\n)?
的任何内容。
请记住:使用?
或*
量化的模式始终成功,因为它们在语义上与
分别和任何可以匹配零次:
$ perl -le 'print scalar "abc" =~ /(?!)*/' 1
虽然我想不出我用过这种方式的时间,但{em> m 为零的{m,n}
量词,例如,
将始终成功,因为 m 是最小重复次数。 {0}
量词是一个包含完整性的病理案例。
所有这些都表明我们或多或少地对line1
案件感到幸运。 ^
匹配开头,?
- 量化模式未匹配任何内容,然后下一个^
也匹配$data
的开头。
恢复对称性使得模式更清晰:
my $pattern = qr/ (^.+\n)?
^line5\n
(^.+\n)?
/mx;
答案 2 :(得分:1)
我意识到你要求一个Perl解决方案,但无论如何这里是一个Unix grep
解决方案:
grep -C 1 line3 file.txt
输出:
line2
line3
line4
来自grep
联机帮助页:
-C NUM, --context=NUM Print NUM lines of output context. Places a line containing -- between contiguous groups of matches.
答案 3 :(得分:1)
使用unix命令行的功能很大就是这种情况,perl接受它。
尝试类似grep -A 1
或grep -B 1
的内容
它会在你之前/之前给你一行