foreach my $foo (sort lexically @list) { ... } ... sub lexically { # This routine gives us a sort order that more closely matches # what a naive use would expect (ie "9-z" comes before "10-a") # The simple implementation style makes the code easier # to follow my($a_,$b_) = @_; # If we are called by sort the old @_ gets left around # attempt to detect this and grab values from $a and $b if(!defined($a_) || !defined($b_) || ref($a_) || ref($b_) || $#_ != 1) { $a_ = $a; $b_ = $b; } return 0 if($a_ eq "" && $b_ eq ""); return -1 if($a_ eq ""); return 1 if($b_ eq ""); my($a_1,$a_t,$a_2,$b_1,$b_t,$b_2); if($a_ =~ /^(\d+)/) { $a_t = 0; $a_1 = $1; $a_2 = $'; } elsif($a_ =~ /^(\D+)/) { $a_t = 1; $a_1 = $1; $a_2 = $'; } if($b_ =~ /^(\d+)/) { $b_t = 0; $b_1 = $1; $b_2 = $'; } elsif($b_ =~ /^(\D+)/) { $b_t = 1; $b_1 = $1; $b_2 = $'; } if($a_t == 0 && $b_t == 0) { # Both start with a numeric value return lexically($a_2,$b_2) if($a_1 == $b_1); return $a_1 <=> $b_1; } if($a_t == 1 && $b_t == 1) { # Both start with text, fold everything to # lower case (so "A" is the same as "a" # which is what I want, YMMV) my $r = lc($a_1) cmp lc($b_1); return lexically($a_2,$b_2) if($r == 0); return $r; } return -1 if($a_t == 0); return 1; }