簡體   English   中英

如何在Perl中進行模式匹配之前和之后的行匹配?

[英]How do I match the line before and after a pattern match in Perl?

我正在匹配一個模式,並使用$.獲得匹配行$.

我需要在特定模式之前和特定模式之后打印匹配的行,例如:

line1
line2
line3
line4
line5

模式匹配line3 ,我要打印line2line4

如何在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模式匹配。

另請注意,上述模式缺乏通用性。 它工作正常的線路中間的某個位置,但如果你改變它就會失敗line3line1line5

對於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為零, 例如

  • {0,100}
  • {0,}
  • {0}

將始終成功,因為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 1grep -B 1東西,它將在之后/之前給你一行

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM