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

Reply via email to