Reputation: 21
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
Reputation: 21
Thanks Everyone for sharing there thought. it was really insightful and encourage me more to learn.
#!/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
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
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
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
Reputation: 59
while(<Your filehandle name>)
{
if ($string =~ m/search_pattern/g)
{
$_=~ s/append_text/**append_text**/g;
}
close(filehandle name)
Upvotes: -1