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; }