sandeep singh
sandeep singh

Reputation: 21

Append text in the end of line if search pattern is found

This is my first question on this forum :).

I have a file something like:

----File--------
XI39/XM79 XI39/XM79#G XI39/XM79#S XI39/XM79#D XI39/XM79#B XI39/XM79#DN append_text! 
+ search_pattern
+ w=5e-07 l=3.85e-07 sa=4.1e-07 sb=4.1e-07 ad=2.05e-13 as=2.05e-13 pd=1.82e-06

XI57/XM0@1 XI57/XM0@1#G XI57/XM0@1#S XI57/XM0@1#D XI57/XM0@1#B XI57/XM0@1#DN
+ search_pattern
+ w=1e-06 l=3.85e-07 sa=4.1e-07 sb=1.215e-06 ad=2.1e-13 as=4.1e-13 pd=1.42e-06

I want to search for "search_pattern" and if found look at one line above and append "append_text!" in end of line if its not present.

So the output file should be:-

------------output file------

XI39/XM79 XI39/XM79#G XI39/XM79#S XI39/XM79#D XI39/XM79#B XI39/XM79#DN append_text! 
+ search_pattern
+ w=5e-07 l=3.85e-07 sa=4.1e-07 sb=4.1e-07 ad=2.05e-13 as=2.05e-13 pd=1.82e-06

XI57/XM0@1 XI57/XM0@1#G XI57/XM0@1#S XI57/XM0@1#D XI57/XM0@1#B XI57/XM0@1#DN append_text!
+ search_pattern
+ w=1e-06 l=3.85e-07 sa=4.1e-07 sb=1.215e-06 ad=2.1e-13 as=4.1e-13 pd=1.42e-06

I know perl a little so can do file operations but not good at all with pattern matching. Any pointer will be helpful.

Upvotes: 0

Views: 191

Answers (5)

sandeep singh
sandeep singh

Reputation: 21

Thanks Everyone for sharing there thought. it was really insightful and encourage me more to learn.

Based on various reply this is something I wrote and went with:-

#!/usr/bin/perl

use strict;
use warnings;

open(FH, "</home/sksingh/file");
my $this_line = "";
my $line_to_print = "";
while(<FH>) {
    my $last_line = $this_line;
    $this_line = $_;
    $line_to_print = $last_line;
    if ($this_line =~ /search_pattern/) {
        if($last_line =~ /append_txt!/) {
          $line_to_print = $last_line;
        }
        else {
          chomp($last_line);
          $line_to_print = "$last_line" . "psub!\n";
        }
      }
    print $line_to_print;
}
close (FH);

Again thanks for reply.

Currently the input file is of around 100 mb. It in coming days i might have to precess file up till 3 GB. Not sure how this code will scale but for now I am good to go.

---Sandeep---

Upvotes: 1

brian d foy
brian d foy

Reputation: 132920

You can do this with a line buffer. You read lines from the file and save the previous one you've read. When you find a line that matches your criteria, you modify the previous line and output it. The current line becomes the previous line and you keep going:

use v5.12;
use warnings;

chomp( my $previous_line = <> );
while( <> ) {
    chomp;
    if( /search_pattern/ and $previous_line !~ / append_text!\z/ ) {
        $previous_line .= " append_text!";
        }

    say $previous_line;
    $previous_line = $_;
    }

say $previous_line;

This is something that someone on the second day of my Learning Perl could do and understand. There are no fancy regex features.

The same thing works if the previous interesting line is further away. You can keep a small line window array and once you find the line that triggers an action, do whatever you want to the previous lines:

use v5.12;
use warnings;

my $buffer_size = 3;
my @line_window = map { scalar <> } 1 .. $buffer_size;
chomp( @line_window );

while( <> ) {
    chomp;
    if( /search_pattern/ and $line_window[0] !~ / append_text!\z/ ) {
        $line_window[0] .= " append_text!";
        }

    say shift @line_window;
    push @line_window, $_;
    }

say join "\n", @line_window;

Upvotes: 1

Polar Bear
Polar Bear

Reputation: 6818

Desired result can be achieved with perl one liner

perl -007 -pe "s/(#DN)(\s+\+ search_pattern)/$1 append_text!$2/gs" filename

Or you could use following perl code (NOTE: it uses DATA block for test purpose)

use strict;
use warnings;
use feature 'say';

my $data = do { local $/; <DATA> };

$data =~ s/(#DN)(\s+\+ search_pattern)/$1 append_text!$2/gs;

say $data;

__DATA__
----File--------
XI39/XM79 XI39/XM79#G XI39/XM79#S XI39/XM79#D XI39/XM79#B XI39/XM79#DN append_text! 
+ search_pattern
+ w=5e-07 l=3.85e-07 sa=4.1e-07 sb=4.1e-07 ad=2.05e-13 as=2.05e-13 pd=1.82e-06

XI57/XM0@1 XI57/XM0@1#G XI57/XM0@1#S XI57/XM0@1#D XI57/XM0@1#B XI57/XM0@1#DN
 + search_pattern
 + w=1e-06 l=3.85e-07 sa=4.1e-07 sb=1.215e-06 ad=2.1e-13 as=4.1e-13 pd=1.42e-06

Or even better with look behind to not includes append_text! in regular expression (for case if the line before + search_pattern has irregular pattern)

use strict;
use warnings;
use feature 'say';

my $data = do { local $/; <DATA> };

$data =~ s/(?<!append_text!)(\s+\+ search_pattern)/ append_text!$1/gs;

say $data;

__DATA__
----File--------
XI39/XM79 XI39/XM79#G XI39/XM79#S XI39/XM79#D XI39/XM79#B XI39/XM79#DN append_text! 
+ search_pattern
+ w=5e-07 l=3.85e-07 sa=4.1e-07 sb=4.1e-07 ad=2.05e-13 as=2.05e-13 pd=1.82e-06

XI57/XM0@1 XI57/XM0@1#G XI57/XM0@1#S XI57/XM0@1#D XI57/XM0@1#B XI57/XM0@1#DN
+ search_pattern
+ w=1e-06 l=3.85e-07 sa=4.1e-07 sb=1.215e-06 ad=2.1e-13 as=4.1e-13 pd=1.42e-06

Output

----File--------
XI39/XM79 XI39/XM79#G XI39/XM79#S XI39/XM79#D XI39/XM79#B XI39/XM79#DN append_text!
+ search_pattern
+ w=5e-07 l=3.85e-07 sa=4.1e-07 sb=4.1e-07 ad=2.05e-13 as=2.05e-13 pd=1.82e-06

XI57/XM0@1 XI57/XM0@1#G XI57/XM0@1#S XI57/XM0@1#D XI57/XM0@1#B XI57/XM0@1#DN append_text!
 + search_pattern
 + w=1e-06 l=3.85e-07 sa=4.1e-07 sb=1.215e-06 ad=2.1e-13 as=4.1e-13 pd=1.42e-06

Upvotes: 0

ssr1012
ssr1012

Reputation: 2589

We can append the text in more ways.. Lets try this one

Push all your data into array

push(@allline, <DATA>);  

Iterate for loop

for(my $i=0; $i < $#allline; $i++)
{

Catch up the Matched line and previous line

    my $j = $i; $j--;

If matches found then go back to the previous line

    if($allline[$i]=~m/\+\s*search_pattern/)
    {

Check the append_text availability

        if($allline[$j]!~m/append_text/)
        {
            $allline[$j]=~s/$/ \*\*append_text\*\*/;
        }
        elsif($allline[$j]=~m/append_text/)
        {
            $allline[$j]=~s/append_text/\*\*append_text\*\*/;
        }
    }
}

Check your output

print join "", @allline;


__DATA__
XI39/XM79 XI39/XM79#G XI39/XM79#S XI39/XM79#D XI39/XM79#B XI39/XM79#DN append_text! 
+ search_pattern
+ w=5e-07 l=3.85e-07 sa=4.1e-07 sb=4.1e-07 ad=2.05e-13 as=2.05e-13 pd=1.82e-06

XI57/XM0@1 XI57/XM0@1#G XI57/XM0@1#S XI57/XM0@1#D XI57/XM0@1#B XI57/XM0@1#DN
+ search_pattern
+ w=1e-06 l=3.85e-07 sa=4.1e-07 sb=1.215e-06 ad=2.1e-13 as=4.1e-13 pd=1.42e-06

Output

 XI39/XM79 XI39/XM79#G XI39/XM79#S XI39/XM79#D XI39/XM79#B XI39/XM79#DN \*\*append_text\*\*!
 + search_pattern
 + w=5e-07 l=3.85e-07 sa=4.1e-07 sb=4.1e-07 ad=2.05e-13 as=2.05e-13 pd=1.82e-06

 XI57/XM0@1 XI57/XM0@1#G XI57/XM0@1#S XI57/XM0@1#D XI57/XM0@1#B XI57/XM0@1#DN \*\*append_text\*\*
 + search_pattern
 + w=1e-06 l=3.85e-07 sa=4.1e-07 sb=1.215e-06 ad=2.1e-13 as=4.1e-13 pd=1.42e-06

Upvotes: 1

Ansuman Mishra
Ansuman Mishra

Reputation: 59

while(<Your filehandle name>)
{
if ($string =~ m/search_pattern/g) 
{
$_=~ s/append_text/**append_text**/g;
}
close(filehandle name)

Upvotes: -1

Related Questions