| package BitRange; |
| |
| use warnings; |
| use strict; |
| |
| use Data::Dumper; |
| |
| #------------------------------------------------------------------------------- |
| |
| # Takes a string of integers separated by ',' (concat) and ':' (range). Will |
| # return a sorted list of the expanded strings. |
| sub expand($) |
| { |
| my ( $str ) = @_; |
| |
| my @list; |
| for my $e ( split(/,/, $str) ) |
| { |
| if ( $e =~ /([0-9]+):([0-9]+)/ ) |
| { |
| push @list, $_ foreach ( int($1)..int($2) ); |
| } |
| else |
| { |
| push @list, int($e); |
| } |
| } |
| |
| return @list; |
| } |
| |
| #------------------------------------------------------------------------------- |
| |
| sub __combineConsecutiveRanges($$;$$); # because it is called recursively |
| |
| sub __combineConsecutiveRanges($$;$$) |
| { |
| my ( $in, $out, $first, $last ) = @_; |
| |
| # Check if there are any elements in the input list. |
| if ( 0 < scalar @{$in} ) |
| { |
| # Check if we have found any previous range elements. |
| if ( defined $first ) |
| { |
| if ( defined $last ) |
| { |
| # We have at least two in a range. Check if the next one is in |
| # the consecutive range. |
| if ( $last + 1 == $in->[0] ) |
| { |
| $last = shift @{$in}; |
| } |
| # This range is done. Add to the list and start the next range. |
| else |
| { |
| push @{$out}, "$first:$last"; |
| $first = shift @{$in}; |
| $last = undef; |
| } |
| } |
| else |
| { |
| # Only the first element in the range so far. Check if the next |
| # one is in the consecutive range. |
| if ( $first + 1 == $in->[0] ) |
| { |
| $last = shift @{$in}; |
| } |
| # This range is done. Add to the list and start the next range. |
| else |
| { |
| push @{$out}, "$first"; |
| $first = shift @{$in}; |
| $last = undef; |
| } |
| } |
| } |
| # No previous range elements. Get the first one. |
| else |
| { |
| $first = shift @{$in}; |
| $last = undef; # Just in case. |
| } |
| |
| # Iterate again. |
| __combineConsecutiveRanges($in, $out, $first, $last); |
| } |
| # Nothing else in the input list. Add any trailing range elements. |
| elsif ( defined $first ) |
| { |
| push @{$out}, "$first" . ((defined $last) ? ":$last" : ""); |
| } |
| } |
| |
| # Takes a reference to a list of integers. Any set of consecutive integers will |
| # be combined using the ':' character to represent a range |
| # (i.e. 0,1,2,3 => 0:3). The remaining non-consecutive integers will be combined |
| # with ',' character (i.e. 0,2,3,5 => 0,2:3,5). |
| sub compress($) |
| { |
| my ( $in ) = @_; |
| |
| # Next, combine all of the consecutive ranges. |
| my $out = []; |
| __combineConsecutiveRanges( $in, $out ); |
| |
| # Now, combine the non-consecutive elements and return the string. |
| return join( ',', @{$out} ); |
| } |
| |
| #------------------------------------------------------------------------------- |
| |
| 1; |