#!/your/perl/here # demonstrate sorting numerically within a string # # for example, abc2xyz sorts before abc14xyz # use strict; use warnings; my @list = map { $_ . "\n" } qw( a1 a2 a10 a1a a2a a10a a01a a10b a1b2c a1b10c aa1 ); print sort mixed_sort @list; { # closure for caching, etc. my %seen; sub mixed_sort { return $seen{$a,$b} if exists( $seen{$a,$b} ); $seen{$a,$b} = 0; my $re_num = qr/\d+/; my $re_both = qr/^(\d+|\D+)+$/; # split into alpha and numeric fields my @x = $a =~ /$re_both/go; my @y = $b =~ /$re_both/go; my $longest = @x > @y ? @x-1 : @y-1; foreach my $i ( 0..$longest ) { if ( defined( $x[$i] ) and defined( $y[$i] ) ) { if ( ( $x[$i] =~ /^$re_num$/o ) and ( $y[$i] =~ /^$re_num$/o ) ) { $seen{$a,$b} = $x[$i] <=> $y[$i]; # both are numbers } else { $seen{$a,$b} = $x[$i] cmp $y[$i]; } } elsif ( defined( $x[$i] ) ) { $seen{$a,$b} = +1; } elsif ( defined( $y[$i] ) ) { $seen{$a,$b} = -1; } # else they're both undef, and nothing changes yet return $seen{$a,$b} if $seen{$a,$b}; } return $seen{$a,$b} = $a cmp $b; # if all else fails } # end of sub mix_sort } # end of closure for sub mixed_sort __END__