Reputation: 8208
I'm writing a better version of sed basically (I need it for some ETL work).
cat file.txt | transform [regex] [replaceor] [regex] [replaceor] [regex replaceor]...
my %transforms = @ARGV; # convert array (regex,replace,regex,replace) pairs into hash
# want something like this:
# my %transforms = map { qr/$_/ => $_[++]} @ARGV; # grab TWO element of @ARGV at a time
while (my $content = <STDIN>) {
while (my ($scan, $print) = each(%transforms)) {
# $print could be code. Still deciding on that.
my $scan = qr/$scan/; # WANT TO AVOID re-compiling the regex every time
my $transformed = $content =~ s/$scan/$print/re; #
print $transformed;
}
}
Yes, I could do this with brute force and many other ways but this grabbing multiple items from an array has come up for me several times and I wonder if there is a trick to it. Hmm. What about a double map?
Upvotes: 1
Views: 121
Reputation: 386646
You could use
use List::Util qw( pairmap );
my %transforms = pairmap { qr/$a/ => $b } @ARGV;
or
my %paired_args = @ARGV;
my %transforms = map { qr/$_/ => $paired_args{$_} } keys( %paired_args );
But hash keys are always strings. The above is equivalent to
use List::Util qw( pairmap );
my %transforms = pairmap { my $re = qr/$a/; "$re" => $b } @ARGV;
And that is effectively equivalent to the following (or something similar):
my %transforms = pairmap { "(?^u:$a)" => $b } @ARGV;
You're hoping to compile the patterns once each, but this doesn't achieve that. You're actually causing each pattern to be compiled one extra time!
You don't actually need to look up values by key, so an array of arrays would do the trick here.
use List::Util qw( pairmap );
my @transforms = pairmap { [ qr/$a/, $b ] } @ARGV;
while ( my $content = <STDIN> ) {
for ( @transforms ) {
my ( $scan, $print ) = @$_;
$content =~ s/$scan/$print/;
}
print $content;
}
Note how I didn't use /e
. If you were using /e
in the hopes of getting $1
to work, that's not the right approach. Use String::Substitution instead.
For example, you can replace
# Doesn't support $1 and such. Doesn't require `\` to be escaped.
$content =~ s/$scan/$print/;
with
use String::Substitution qw( sub_modify );
# Supports $1 and such. Requires `\` to be escaped.
sub_modify( $content, $scan, $print );
Upvotes: 2