Reputation: 5827
I want to replace in a string the substrings "[ids]", "[order]", and "[limit]" with three other substrings (passed as parameters to my routine).
But I want to cancel the special meaning of "[...]" if "[" or "]" is preceded by "\" ("\[", "\]"). Also "\" should cancel itself: "\\" means "\".
How to implement this in Perl?
Note that we may use something other instead of "[ids]", "[order]", and "[limit]". This is not set in stone.
Upvotes: 1
Views: 181
Reputation: 5827
#!/usr/bin/perl
use strict;
use warnings;
sub replace_squared_terms {
my ($str, $hash) = @_;
my $new = "";
for(;;) {
return $new if $str eq "";
if($str =~ /^([^\[\]\\\/]+)(.*)/s) {
$new .= $1;
$str = $2;
} elsif($str =~ /^\[([^\/\[\]]+)\](.*)/s) {
die "Wrong template" unless exists $hash->{$1};
$new .= $hash->{$1};
$str = $2;
} elsif($str =~ /^\\(.)(.*)/s) {
$new .= $1;
$str = $2;
} else {
die "Wrong template";
}
}
}
my $str = "[a] [b] \\[ [a] \\\\";
print replace_squared_terms($str, {a=>"123", b=>"XYZ"}), "\n";
Upvotes: 0
Reputation: 33928
Here's one way you could do it:
sub replace{
my ($str, $ids, $order, $limit) = @_;
$str =~ s/(?<!\\)((?:\\.)*) \[ (?: (ids) | (order) | limit ) \]/
$1 . ($2? $ids: $3? $order: $limit)/gsex;
return $str;
}
Example:
print replace <<'_STR_', '<1DZ>', '<0RD3RZ>', '<L1M1TZ>';
[ids][order][limit]
\[ids]\\[ids]\\\[ids]
_STR_
Output:
<1DZ><0RD3RZ><L1M1TZ>
\[ids]\\<1DZ>\\\[ids]
Upvotes: 0
Reputation: 386621
Why don't you use an existing templating module instead of inventing yet another one?
Anyway, here's a parser that will handle your format.
my %replace = (
ids => ...,
...
);
my $out = '';
for ($in) {
if (/\G ( (?: [^\\\[\]]+ | \\. )+ ) /xsgc) {
$out .= $1;
redo;
}
if (/\G \[ ( (?: [^\\\[\]]+ | \\. )+ ) \] /xsgc) {
die if !exists($replace{$1});
$out .= $replace{$1};
redo;
}
die if !/\G\Z/xsgc;
}
Upvotes: 2