use warnings; use strict; my $str = '1-5,6a-e,7,10-13'; my @ranged; foreach ( split ',', $str ) { if ( /^(\d+)$/ ) { push @ranged, $1; } elsif ( /^(\d+)([a-z]+)-([a-z]+)$/ ) { push @ranged, map { "$1$_" } $2..$3; } elsif ( /^(\d+)-(\d+)$/ ) { push @ranged, $1..$2; } else { die "Don't know how to interpret '$_'"; } } print join "\n", @ranged;