简体   繁体   中英

Regex/Perl to match blocks of text that contain a string

So I have a log file that looks something like this:

EVENT-header
apple
orange
peach
blueberry

EVENT-header
bike
car
blueberry

EVENT-header
reddit
hacker news
stack overflow
slashdot?
voat

What I am trying to do is extract the blocks of text (from EVENT-header to the two newlines before the next EVENT-header) that contain the word "peach".

I think this is a problem that regex would solve, but I am having trouble making regex that does this. Here's what I have come up so far:

's/EVENT-header((?!\n\n).)+peach((?!\n\n).)+\n\n/&/p'

I'm not an expert at this. Is there an easy way to do it using regex/perl?

You can do this easily using paragraph mode which makes perl read blocks of text delimited by blank lines

perl -00 -ne'print if /peach/' logfile.log

If you prefer a full program file then it looks like this

use strict;
use warnings;

open my $fh, '<', 'logfile.log' or die $!;

{
    local $/ = '';

    while ( <$fh> ) {
        print if /peach/;
    }
}
EVENT-header\n[\s\S]*?(?=(?:\n\nEVENT-header|$))

You can use this.See demo.

https://regex101.com/r/hR7tH4/3

There are various ways to do this, with multiline regex match being a good candidate. If the data file is as regular as it appears, specifically with each "record" separated by the marker 'EVENT-header', then you can also use the trick of setting $/ (aka $RS aka $INPUT_RECORD_SEPARATOR) to be this marker and then slurping the file into an array. You'll get an array entry for each record in the file, and then it's trivial to loop over the array, select the elements that match 'peach', and print out the entire containing record.

For example:

#!/usr/bin/perl -w
use strict;

$/='EVENT-header';
my (@entries, $entry);
my $infile = 'data.txt';

open(IN, "<$infile") or die "Aaargh: $^E\n";
@entries = <IN>;
chomp @entries;
close(IN);

foreach $entry (@entries) 
{
  if ($entry =~ m/peach/)
  {
    print "matching entry: $entry\n";
  }
}

Borodin has already given best solution for your question. But here is a code in case you don't want use one liner:

#!/usr/bin/perl
use warnings;
use strict;

local $/ = "";  #to enable paragraph mode

open my $fh, "<", "input.log" or die "Unable to open file: $!";

while (my $line = <$fh>)
{
    chomp $line;
    if ($line =~ m/peach/)
    {
        print $line, "\n";
    }   
}

Output:

EVENT-header
apple
orange
peach
blueberry

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM