Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Conditional Search and Replace

by PyrexKidd (Monk)
on Apr 30, 2010 at 23:41 UTC ( [id://837866]=perlquestion: print w/replies, xml ) Need Help??

PyrexKidd has asked for the wisdom of the Perl Monks concerning the following question:

I need to search a file for one of three patterns and replace it with one of three patters.

currently my code snippet looks like this:

while(<INFILE>){ $_ =~ s/$searchPattern1/$repalcePattern1/g; $_ =~ s/$searchPattern2/$replacePattern2/g; $_ =~ s/$searchPattern3/$replacePattern3/g; print OUTFILE $_; } # end while

Is there perhaps a more elegant way to do this? Also I would Like to print to screen conditionally based on the pattern replaced ie:

if ($_ == s/$searchPattern1/){ print("$searchPattern1 replaced with $replacePattern1 \n"); }elsif ($_ == s/$searchPattern2/){ print("$searchPattern2 replaced with $replacePattern2 \n"); }elsif ($_ == s/$searchPattern3/){ print("$searchPattern3 replaced with $replacePattern3 \n"); }else{ print("Search Patterns not found"); }

although at that point I can maybe change it to:

while(<INFILE>){ if ($_ == s/$searchPattern1/){ $_ =~ s/$searchPattern1/$repalcePattern1/g; print("$searchPattern1 replaced with $replacePattern1\n"); }elsif ($_ == s/$searchPattern2/){ $_ =~ s/$searchPattern1/$repalcePattern1/g; print("$searchPattern2 replaced with $replacePattern2\n"); }elsif ($_ == s/$searchPattern3/){ $_ =~ s/$searchPattern1/$repalcePattern1/g; print("$searchPattern3 replaced with $replacePattern3\n"); }else{ print("Search Patterns not found"); } print OUTFILE $_; } # end while
but that doesn't seem to be working... also as an aside is there a way to remove all the spaces at the end of a line and add a new line character? ie:
<SOURCEFILE> foo bar <\n> foobar <\n> BlahBlah Blah <\n> to: foo bar<\n> foobar<\n> BlahBlah Blah<\n>

Replies are listed 'Best First'.
Re: Conditional Search and Replace
by ikegami (Patriarch) on May 01, 2010 at 00:16 UTC

    Is there perhaps a more elegant way to do this?

    If you you input and output redirection, you can let the shell do the file handling for you.

    while (<>) { s/$searchPattern1/$repalcePattern1/g; s/$searchPattern2/$replacePattern2/g; s/$searchPattern3/$replacePattern3/g; print; }

    but that doesn't seem to be working

    while (<>) { if (s/$searchPattern1/$repalcePattern1/g) { warn("$searchPattern1 replaced with $replacePattern1\n"); } elsif (s/$searchPattern2/$repalcePattern2/g) { warn("$searchPattern2 replaced with $replacePattern2\n"); } elsif (s/$searchPattern3/$repalcePattern3/g) { warn("$searchPattern3 replaced with $replacePattern3\n"); } else { warn("Search Patterns not found\n"); } print; }

    Note that you used to search for all three patterns. Now you stop after one succeeds in replacing something.

    is there a way to remove all the spaces at the end of a line and add a new line character?

    s/\s*\z/\n/;
Re: Conditional Search and Replace
by FalseVinylShrub (Chaplain) on May 01, 2010 at 08:03 UTC

    Hi

    As I've not done much coding for awhile, your request for a 'more elegant' solution got me thinking. I've come up with this, definitely over-engineered and whether it's more elegant or not is debatable...

    But the key change is to make the list of search-and-replacements into an array and iterate through that, rather than write the code to test and print multiple times. I think, elegant or not, this code would be easier to modify.

    I also couldn't resist implementing your logging requirement as a trigger sub passed in from the outside.

    I implemented your whitespace cleaning as the last search and replace in the list. Note that the list is processed in order as there may be dependencies between the search and replace terms. This preserves the semantics of your original and that's why I used an array of arrays rather than a hash-based structure which was the first thing I though of.

    So anyway here it is for comments ;-)

    #!/usr/bin/perl use warnings; use strict; # runs through all lines from STDIN or ARGV files while (<>) { $_ = search_and_replace( $_, \&log_if_replaced ); print; } # Try each replacement, in order, and call the trigger with the result # and return the (possibly modified) text sub search_and_replace { my $text = shift; # the text my $trigger = shift; # optional subref to handle matches foreach ( search_and_replace_operations() ) { my ($pattern, $replacement) = @{ $_ }; my $matched; # did it match or not? $matched = $text =~ s{$pattern}{$replacement}g; $trigger->($matched, $text, $pattern, $replacement) if $trigger; } return $text; } # the replacements... (could be read from a file, etc) sub search_and_replace_operations { return ( [ qr/searchregexp1/, 'replacementstring1' ], [ qr/[0-9]+/, 'I am not a number' ], # etc [ qr/\s+$/, "\n" ], # standardize whitespace at end ); } # this trigger gets called for every match attempt # and logs a message for every replacement. sub log_if_replaced { my $matched = shift; my $text = shift; my $pattern = shift; my $replacement = shift; foreach ($text, $pattern, $replacement) { # escape whitespace for readable logs s{([\s])}{ escape_whitespace($1) }ge; } print STDERR "'$pattern' -> '$replacement' result: '$text'\n" if $matched; }; # make whitespace readable for logs sub escape_whitespace { my $char = shift; return ' ' if $char eq " "; return '\n' if $char eq "\n"; return '\t' if $char eq "\t"; return '\x{' . (ord($char)) .'}'; }

    Just nice to have time to think about something so much ;-)

    FalseVinylShrub

    Disclaimer: Please review and test code, and use at your own risk... If I answer a question, I would like to hear if and how you solved your problem.

Re: Conditional Search and Replace
by Hue-Bond (Priest) on May 01, 2010 at 08:53 UTC

    This is my take at it:

    use warnings; use strict; my @repls = ( [ qr/pat1/, 'repl1' ], [ qr/pat2/, 'repl2' ], [ qr/pat3/, 'repl3' ], ); my $txt = <<'EOF'; This is some example (pat1) text which will be (pat3) modified according (pat2) to some replacement (pat2) rules. EOF foreach my $r (@repls) { $txt =~ s/$r->[0]/$r->[1]/eg; } print $txt; __END__ This is some example (repl1) text which will be (repl3) modified according (repl2) to some replacement (repl2) rules.

    If you want to capture things and use them, it gets more (too?) complicated:

    use warnings; use strict; my @repls = ( [ qr/pat(\d+)/, 'qq{repl$1}' ], ); my $txt = <<'EOF'; This is some example (pat42) text EOF foreach my $r (@repls) { $txt =~ s/$r->[0]/$r->[1]/eeg; } print $txt; __END__ This is some example (repl42) text

    Note the use of qq{} in single quotes and the double eval in the substitution. The first eval turns $r->[1] into qq{repl$1} and the second one turns that into repl42.

    --
     David Serrano
     (Please treat my english text just like Perl code, i.e. feel free to notify me of any syntax, grammar, style and/or spelling errors. Thank you!).

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://837866]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others admiring the Monastery: (1)
As of 2024-04-25 01:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found