Compile your template in the Perl substring:
sub compile { use feature 'switch'; my($pattern) = @_; die "illegal pattern" unless $pattern =~ /^[-xo]+$/; my($search,$replace); my $i = 0; for (split //, $pattern) { given ($_) { when ("x") { $search .= "."; $replace .= "x"; } when ("o") { $search .= "(?<sub$i>.)"; $replace .= "\$+{sub$i}"; ++$i; } when ("-") { $search .= "(?<sub$i>.*)"; $replace .= "\$+{sub$i}"; ++$i; } } } my $code = q{ sub { local($_) = @_; s/^SEARCH$/REPLACE/s; $_; } }; $code =~ s/SEARCH/$search/; $code =~ s/REPLACE/$replace/;
To be more concise, you can write
sub _patref { '$+{sub' . $_[0]++ . '}' } sub compile { my($pattern) = @_; die "illegal pattern" unless $pattern =~ /^[-xo]+$/; my %gen = ( 'x' => sub { $_[1] .= '.'; $_[2] .= 'x' }, 'o' => sub { $_[1] .= "(?<sub$_[0]>.)"; $_[2] .= &_patref }, '-' => sub { $_[1] .= "(?<sub$_[0]>.*)"; $_[2] .= &_patref }, ); my($i,$search,$replace) = (0,"",""); $gen{$1}->($i,$search,$replace) while $pattern =~ /(.)/g; eval "sub { local(\$_) = \@_; s/\\A$search\\z/$replace/; \$_ }" or die $@ ; }
Testing:
use v5.10; my $replace = compile "xxox-x"; my @tests = ( [ deadbeef => "xxaxbeex" ], [ deadabbabeef => "xxaxabbabeex" ], ); for (@tests) { my($input,$expect) = @$_; my $got = $replace->($input); print "$input => $got : ", ($got eq $expect ? "PASS" : "FAIL"), "\n"; }
Output:
deadbeef => xxaxbeex : PASS deadabbabeef => xxaxabbabeex : PASS
Note that you will need Perl 5.10.x for given ... when .
source share