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.
|