use strict; use warnings; # This function takes a "range string" and returns # a list that can be used in a Perl array slice. # Some examples should clarify: # Range string Return list # "4" (4) # "4-6" (4,5,6) # "5-" (5,6,7,...,$maxind) # "-2" (0,1,2) sub range_to_list { my $maxind = shift; # max index of (zero-based) list my $range = shift; # a "range string" (see examples above) my @ilist = split /-/, $range, 2; my $nlist = @ilist; $nlist == 1 || $nlist == 2 or die "range_to_list $nlist out of range"; if ( $nlist == 1 ) { $ilist[0] =~ /^\d+$/ or die "range_to_list, '$ilist[0]' not numeric"; $ilist[0] <= $maxind or die "range_to_list, '$ilist[0]' out of range"; return @ilist; } if ( $ilist[0] eq '' ) # e.g. "-5" case { $ilist[1] =~ /^\d+$/ or die "range_to_list, '$ilist[1]' not numeric"; $ilist[1] <= $maxind or die "range_to_list, '$ilist[1]' out of range"; return ( 0 .. $ilist[1] ); } if ( $ilist[1] eq '' ) # e.g. "3-" case { $ilist[0] =~ /^\d+$/ or die "range_to_list, '$ilist[0]' not numeric"; $ilist[0] <= $maxind or die "range_to_list, '$ilist[0]' out of range"; return ( $ilist[0] .. $maxind ); } # e.g. "3-5" case $ilist[0] =~ /^\d+$/ or die "range_to_list, '$ilist[0]' not numeric"; $ilist[1] =~ /^\d+$/ or die "range_to_list, '$ilist[1]' not numeric"; return ( $ilist[0] .. $ilist[1] ); } my $maxind = 10; print "maxind=$maxind\n"; for my $rstr ( "x", "1-2-3", "0", "10", "11", "4", "4-6", "7-", "-2", "-10", "-11", "-0", "10-", "11-" ) { print "rstr:$rstr:"; my @ret; eval { @ret = range_to_list( $maxind, $rstr ) }; if ($@) { print "...exc:$@"; } else { print "...ret:@ret:\n"; } } my @apples = ( ":zero:", ":one:", ":two:", ":three:", ":four:" ); print "apples ", @apples[range_to_list( $#apples, "1-3" )], "\n";