> I have created a simple test, which compares results of native
> perl s/// (via eval) and proposed template 'replace' vmethod.

After thinking a bit, I understand that trying to recreate perl
s/// behavior in details is a bad idea. I think that reasonable
level of details is simulating perl's $1, $2 etc backreferences,
with possibility to escape $ with backslash, and to escape
backslash itself before $1 (etc). So I throw out \1, \2 tests from
my vmeth_replace.t and added some other tests. You can find it
here: http://martynoff.info/tt2/

Here is my version of 'replace' vmethod, which satisfies the test:

    'replace' => sub {
        my ($text, $pattern, $replace, $global) = @_;
        my ($matched, $after, @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];
            $after   = substr($text, $+[0]);
            @start   = @-;
            @end     = @+;

            # first, collect all matched groups to array
            my @backrefs;
            for (my $i = 0; $i < @start; $i++) {
                push @backrefs,
                    substr( $text, $start[$i], $end[$i] -
$start[$i] );
            }

            # just replace whole match :)
            $matched = $replace;

            # replace the $1, $2, etc. placeholders
            # in reverse order (to ensure we do $10 before $1)
            $matched =~ s{
                \\(\\|\$)      # an escaped backslash (\\) or $
sign (\$)
                |
                \$(\d+)        # backreference
            }{
                $1 || $backrefs[$2]
            }gxoe;

            # add the modified $matched output to the result and
loop if global
            $result .= $matched;
            $text    = $after;
            last unless $global && length $text;
        }
        return $result . $text;
    },


(It is also available in separate file)


-- 
Sergey Martynoff


_______________________________________________
templates mailing list
[email protected]
http://lists.template-toolkit.org/mailman/listinfo/templates

Reply via email to