Nik Clayton wrote:
> In the same spirit -- not being able to use backrefs in .replace() is why I
> wrote Template::Plugin::Subst. I'm (obviously) biased, but it would seem
> to be an appropriate addition to the core.
Hi Nik,
Sorry I wasn't aware of your module, but it certainly looks like the kind
of robust and properly thought-out solution that we need. Excellent job!
I noted one minor problem. In the rather extreme case of having more than
9 backreferences, the $10, $11, etc, placeholders wouldn't get replaced
because they would previously have been munched away by $1.
foreach my $i (1..$#saved_match_start) {
Reversing the order of replacement fixes the problem.
for (my $i = $#saved_match_start; $i; $i--) {
I was also able to re-write it using a loop (tail-recursion style)
rather than recursively calling itself. Although I preferred the
elegance of your recursive approach, this way makes it a little easier
to patch directly into $Template::Stash::SCALAR_OPS without having to
create a separate named subroutine that we can recursively call.
So with your blessing, I'll include the following as the new replace()
virtual method.
'replace' => sub {
my ($text, $pattern, $replace, $global) = @_;
my ($matched, $after, $backref, @start, @end);
my $result = '';
$global = 1 unless defined $global;
while ($text =~ m/$pattern/) {
if($#- == 0) {
# no captured groups so do a simple search and replace
if($global) { $text =~ s/$pattern/$replace/g }
else { $text =~ s/$pattern/$replace/ }
last;
}
# extract the bit before the match, the match itself, the
# bit after and the positions of all subgroups
$result .= substr($text, 0, $-[0]) if $-[0];
$matched = substr($text, $-[0], $+[0] - $-[0]);
$after = substr($text, $+[0]);
@start = @-;
@end = @+;
# do the s/// leaving the placeholders (literally '$1' etc) in place
$matched =~ s/$pattern/$replace/;
# then replace the $1, $2, etc., placeholders in reverse order
# to ensure we do $10 before $1
for (my $i = $#start; $i; $i--) {
$backref = substr( $text, $start[$i], $end[$i] - $start[$i] );
$matched =~ s/\$$i/$backref/g;
}
# add the modified $matched output to the result and loop if global
$result .= $matched;
$text = $after;
last unless $global && length $text;
}
return $result . $text;
},
Many thanks.
A
_______________________________________________
templates mailing list
[email protected]
http://lists.template-toolkit.org/mailman/listinfo/templates