in reply to Sorting on Section Numbers

Fundamentally, you want to split on both dots and number-letter borders. Fortunately, split can be told to return its delimiters by including parentheses around the matching class. By doing that, you'll also need to get rid of the periods it matches with grep. So, this should split up arbitrarily nested section titles.
my @a = qw/1 2 2.2 2.13 2.1.7 3.4a 10.4a.3b.8/; my @sortables = map { [grep /[^\.]/, split/([\.a-z])/, $_] } @a; print join "\n", map join(' ', @{$_}), @sortables;

Your sort then just needs to have a function which splits up the entries and compares them.

my @list = qw/1 10.4a.3b.8 2.2 2 2.13 3.4a 2.1.7 /; print join "\n", sort compare @list; sub compare { my @a = grep /[^\.]/, split/([\.a-z])/, $a; my @b = grep /[^\.]/, split/([\.a-z])/, $b; { my ($c, $d) = (shift @a, shift @b); (!defined $c and defined $d) and return -1; ( defined $c and !defined $d) and return 1; (!defined $c and !defined $d) and return 0; ($c > $d) and return 1; ($c < $d) and return -1; redo; } }

You should avoid repeatedly splitting the lists by caching the split results.

my @list = qw/1 10.4a.3b.8 2.2 2 2.13 3.4a 2.1.7 /; my @cache = map { [grep /[^\.]/, split/([\.a-z])/, $_] } @list; print join("\n", map("@$_", sort compare @cache)); sub compare { my @a = @$a; my @b = @$b; { my ($c, $d) = (shift @a, shift @b); (!defined $c and defined $d) and return -1; ( defined $c and !defined $d) and return 1; (!defined $c and !defined $d) and return 0; ($c > $d) and return 1; ($c < $d) and return -1; redo; } }
There may be an error stuck somewhere in here; my test set was just what is in the above code. Hope this works for you.