I've been doing the
Perl Weekly Challenges. This one
was to implement the Ackermann function and parse URLs.
The Ackermann function is famously prone to huge numbers, so I
restricted my demonstration to the useful values. Even so, let's
pretend we can do it properly:
use Memoize;
memoize('ackermann');
use Math::BigInt;
sub ackermann {
no warnings 'recursion';
my ($m,$n)=@_;
if ($m==0) {
return $n+1;
} elsif ($n==0) {
return ackermann($m-1,1);
} else {
return ackermann($m-1,ackermann($m,$n-1));
}
}
As a programming exercise, this is mostly a case of "be careful what
you wish for". I didn't dig into further optimisations, because the
results aren't actually useful for anything…
For the URL parser I decided to use named captures, since I haven't
done much with them before.
sub urlparse {
my ($url)=@_;
my %match;
Most, but not all, URLs have a // to set off scheme from other
content. I'm trying to be universal, so let's parse them first. Path,
query and fragment are kept back unparsed for later consideration.
Note the double-parenthesising: an outer non-capturing pattern with
the set-off characters (like the @ after userinfo), and an inner
capturing pattern to catch the actual useful bits.
Note also that I have to catch the named patterns %+ into a normal
hash before %+ goes out of scope at the end of the block.
if ($url =~ m!//!) {
$url =~ m!^(?<scheme>.*?)://(?:(?:(?<userinfo>.*)@)?(?<host>[-_a-z0-9]+)(?::(?<port>[0-9]+))?)?(?<pqf>.*)!;
map {$match{$_}=$+{$_}} keys %+;
If there's no //, break on the last colon: everything before is
scheme, everything after is path/query/fragment. (I didn't even know
this was valid, but apparently so.)
} else {
$url =~ m!^(?<scheme>.*):(?<pqf>[^:]*)!;
map {$match{$_}=$+{$_}} keys %+;
}
Then take the path-query-fragment, parse it into its component
bits, and delete the raw data.
$match{pqf} =~ m!(?<path>[^?#]*)(?:\?(?<query>[^#]*))?(?:\#(?<fragment>.*))?$!;
map {$match{$_}=$+{$_}} keys %+;
delete $match{pqf};
return \%match;
}
Comments on this post are now closed. If you have particular grounds for adding a late comment, comment on a more recent post quoting the URL of this one.