http://qs1969.pair.com?node_id=223687

superpete has asked for the wisdom of the Perl Monks concerning the following question:

I know this topic has been beaten to death, but I'm not satisfied with the code I came up with, and am looking for a neat/elegant way.

Purpose: sort a list of strings in a way that is useful to humans - so that "foo2bar" comes before "foo10bar", and so forth.

Here is my ugly code (which I think works)

```sub sort_n {
return
map
{
\$_->[0]
}
sort
{
my \$l = @{\$a->[1]} < @{\$b->[1]}
? scalar @{\$a->[1]}
: scalar @{\$b->[1]} ;

for (my \$n=0; \$n<\$l; \$n++) {
if ( \$a->[1][\$n] =~ /^(\D+)\$/ ) {
if ( \$b->[1][\$n] =~ /^(\D+)\$/ ) {
my \$tmp = \$a->[1][\$n] cmp \$b ->[1][\$n];
return \$tmp if \$tmp;
} else {
return 1;
}
} else {
if ( \$b->[1][\$n] =~ /^(\D+)\$/ ) {
return -1;
} else {
my \$tmp = \$a->[1][\$n] <=> \$b ->[1][\$n];
return \$tmp if \$tmp;
}
}
}

return @{\$a->[1]} <=> @{\$b->[1]};
}
map
{
[
\$_ ,
[
# each element of @_ is split on boundaries
# between digit and nondigit
split (
/(?:(?<=\d)(?=\D))|(?:(?<=\D)(?=\d))/,
\$_
)
]
]
}
@_;
}