[英]How do I match the line before and after a pattern match in Perl?
我正在匹配一個模式,並使用$.
獲得匹配行$.
我需要在特定模式之前和特定模式之后打印匹配的行,例如:
line1
line2
line3
line4
line5
模式匹配line3
,我要打印line2
和line4
。
如何在Perl中進行模式匹配? 誰能幫我?
提前致謝
森提爾
您需要通常稱為上下文的內容。 獲取上下文的最簡單方法是使用變量自己維護它:
#!/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
在整個文件都為標量的情況下,編寫模式,使其捕獲line3
之前和之后的行。 /m
修飾符特別有用:
將字符串視為多行。 也就是說,將
^
和$
從匹配字符串的開頭或結尾更改$
匹配字符串中任意位置的任何行的開頭或結尾。
下面的模式使用/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
之后的line5
), ^
無處可匹配,而是將模式更改為
my $pattern = qr/ ^(.+\n)?
^line5\n
(^.+\n)?
/mx;
輸出
line4
我們可能會在這里停止,但是模式中的不對稱是令人不愉快的。 為什么只針對一種情況而不針對另一種情況工作? 對於line1
, ^
匹配$data
的開頭,然后不匹配(.+\\n)?
。
記住:用?
量化的模式 或*
總是成功的,因為它們在語義上與
分別,並且任何事物都可以匹配零次:
$ perl -le 'print scalar "abc" =~ /(?!)*/' 1
盡管我想不出有什么時間使用過這種方式,但它是一個{m,n}
量詞,其中m為零, 例如 ,
將始終成功,因為m是最小重復次數。 {0}
量詞是出於完整性考慮的病理情況。
這一切都表明我們多少對line1
案例感到幸運。 ^
一開始就匹配了?
量化模式不匹配任何內容,然后下一個^
也匹配$data
開頭。
恢復對稱可以使模式更清晰:
my $pattern = qr/ (^.+\n)?
^line5\n
(^.+\n)?
/mx;
我知道您要求使用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.
在這種情況下,使用unix命令行功能非常有用,perl對此很滿意。 嘗試類似grep -A 1
或grep -B 1
東西,它將在之后/之前給你一行
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.