Have you wished for Javascript escape()-style function in Perl?
Perl has, by default, all sorts of cool escape functions, but
regrettably none for specifically handling URIs.
Regrettably, writing one is not easy in Perl (tr/// doesn't do
multi-byte and "smart" stuff), but it's entirely possible and everyone
can do that in one sitting...
For The Rest Of Us
Of course, there's a CPAN module URI for this (in
Debian, last time I checked, it's in liburi-perl package
and it's dependant for LWP, a cool module everyone should have =)
Its canonical function is extremely handy.
Regrettably this method translates spaces to %20, which is
overkill. (The Standard says you can always use +'es instead of
%20...)
$escaped = URI->new($url)->canonical->as_string;
But... what to do if we don't want to use that module???
The Boring Way
This is the iterative approach. It just takes the string character
by character; if character is not alphanumeric, it will be escaped
before it's added to result string.
(This uses POSIX module, though it wouldn't need to).
sub quote {
my $str = shift || die "Some coder used quote() with no args. Fool.\n";
my $newstr;
$str =~ tr/ /+/; # Convert spaces to +'es
# Iterate over characters; If it's alphanumeric (or plus), use it
# as it is, else insert it as a %XX hex escape.
for(my $n = 0; $n < length($str); $n++) {
my $char = substr($str,$n,1);
if($char eq '+' or POSIX::isalnum($char)) {
$newstr .= $char;
} else {
$newstr .= "%" . uc sprintf("%02x",ord($char));
}
}
return $newstr;
}
The Kewl Way
TIMTOWTDI - this one uses map { ... } function, which
looks hairier and is thus infinitely cooler.
sub quote ($) {
my $str = shift || die "Some coder used quote() with no args. Fool.\n";
$str =~ tr/ /+/;
return join "", map {
if(tr/a-zA-Z+// == 0) {
$_ = "%" . uc sprintf("%02x",ord);
} else {
$_ = $_;
}
} split //, $str;
}
(Thought-job of the day: Figure out what kind of stuff return,
join, map, and split do here. Spoiler: We
split the array with split, then map each character to the
quoted/unquoted character, and then join our return
value. =)