[Perth-pm] Using \L and \E inside a variable, inside a substitution s///

James Bromberger james at rcpt.to
Sun Oct 24 18:51:50 PDT 2010


On 25/10/2010 07:58, Peter Hallam wrote:
>> my $url = 'http://www.FOo.COm/wibbLE';
>> my $search = '^([^:]+://[^/]+)/?(.*)?$';
>> my $replace = '\L$1\E/$2';
>> print $url if $url =~ /$search/$replace/;
> Given $url and $search I came up with:
>   print $url if $url =~ s|$search|lc($1)."/$2"|e;
>
> However, I'd be tempted to capture the forward slash to with:
>   my $search = '^([^:]+://[^/]+)(/?.*)?$';
>
> Which then alleviates the need to use the pipe character in the substitution:
>
>   print $url if $url =~ s/$search/lc($1).$2/e;
Thanks Peter,

I was also trying to see if I could guarantee that the URL would end up
with a trailing slash after the hostname, as well as not having
(possibly untrusted) replacement text as an expression in the RHS.

I suspect using any escape sequence (either \L or back references
$1...n) in the RHS (replacement) part of a substitution (s///) is going
to only work if it is a literal, not inside a variable. Passing just
'$1' inside a variable without "/e" (eval) isn't going to expand, and as
soon as you have "/e" or eval, then your replacement string could be
armed with Bad Stuff (like $replace = 'unlink "/some/file"').

My next test case I hit was:
my $search = '^(http://[^/:]+):80(/.*)$';
my $replace = '$1$2';
$url =~ s!$search!$replace!;

In order to strip out default port , but again, I end up with $url =
'$1$2', not the sanitised string.


So I think that, if I fetch my replace string from the database, and a
add a pair of double quotes within the string, and use /ee (yep, double
e), then I think it works:
my $search = '^([^:]+://[^/]+(:\d+)?)/?(.*)?$'; # From database
my $replace = '\L$1\E/$3'; # From database
my $url = 'http://www.FOo.COm:80/wibbLE';
$replace = '"' . $replace . '"';
print $url . "\n" if $url =~ s/$search/$replace/ee; # Gives:
http://www.foo.com:80/wibbLE

Of course, then using:
my $search = '^([^:]+://[^/]+(:\d+)?)/?(.*)?$'; # From database
my $replace = '" eq ""; print time(); print "';
my $url = 'http://www.FOo.COm:80/wibbLE';
$replace = '"' . $replace . '"';
print $url . "\n" if $url =~ s/$search/$replace/ee;

Just gives me the time (safest thing I could think of), and potentially
a lot of trouble. So lastly:
my $search = '^([^:]+://[^/]+(:\d+)?)/?(.*)?$'; # From database
my $replace = '\L$1\E/$3'; # From database
$replace =~ s/"/\\"/g; # Protection from embedded code
$replace = '"' . $replace . '"'; # Put in a string for /ee
my @urls = qw ( http://www.FOo.COm:80/wibbLE http://www.FOo.COm/
http://www.FOo.COm );
foreach (@urls) {
  print "$_\n" if s/$search/$replace/ee;
}


Hmm. Ponderous. :)

  James
-- 
*James Bromberger*
Aus Mobile: +61 422 166 708
Email: james /_AT_/ rcpt.to, Web: www.james.rcpt.to
<http://www.james.rcpt.to/>
MSN: james/_AT_/rcpt.to, AIM: JamesEBromberger, Skype: james.bromberger
(/_AT_/ -> @)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.pm.org/pipermail/perth-pm/attachments/20101025/2c6cc31b/attachment.html>


More information about the Perth-pm mailing list