List Info

Thread: Correct replace vmethod




Correct replace vmethod
user name
2006-02-02 04:35:42
> 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
templatestemplate-toolkit.org
http://lists.template-toolkit.org/mailman/listinfo/t
emplates
[1]

about | contact  Other archives ( Real Estate discussion Medical topics )