> 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
templates template-toolkit.org
http://lists.template-toolkit.org/mailman/listinfo/t
emplates
|