You didn't provide enough testing data for the border cases. When doing several replacements on the same string, it's usually faster to store the regexes and replacements in a hash, and run just one replacement. It's not clear whether it's possible in your case, but it works for the simple input you provided:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Benchmark qw{ cmpthese };
my $match_list = 'a/ere,c/ere';
my $markup = 'TY:X{a} X{c}';
my $attrs = 'TY a=errt c=rrrdd';
my $tag = 'TY';
sub first_draft {
my %xlist = map{ split(/\//, $_, 2) }
grep{ m/\// } split(/,/, $match_list);
$attrs =~ s/\A$tag //;
my @attr = $attrs =~ /(?:\A| )(.+?)(?=(?: \w+=|\z))/g;
for (@attr) {
my ($name, $value) = split(/=/,$_);
if (exists $xlist{$name} && defined $xlist{$name}) {
$xlist{$name} = undef;
$markup =~ s/X\{$name\}/$value/g;
} else {
$markup = '';
last;
}
}
$markup
}
sub choroba {
my %xlist = map split(m=/=, $_, 2), grep m=/=, split /,/, $match_l
+ist;
$attrs =~ s/\A$tag //;
my @attr = $attrs =~ /(?:\A| )(.+?)(?=(?: \w+=|\z))/g;
my %replace = map split /=/, @attr;
$markup =~ s/X\{(.*)\}/$replace{$1}/g;
$markup
}
use Test::More;
is first_draft(), choroba(), 'same';
done_testing(1);
warn Dumper(first_draft());
cmpthese(shift || -1, {
'first_draft' => \&first_draft,
'choroba' => \&choroba,
});
Output:
ok 1 - same
1..1
$VAR1 = 'TY:errt rrrdd';
Rate first_draft choroba
first_draft 135244/s -- -57%
choroba 312785/s 131% --
($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord
}map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,