use strict;
use warnings;
no warnings 'numeric';

my @numbers = ( 1, 2, 4, 5, 6, 7, 9, 13, 24, 25, 26, 27 );
print "@numbers\n";
my $number_string = format_number_list( @numbers );
print "$number_string\n";
@numbers = expand_number_list( $number_string );
print "@numbers\n\n";

@numbers = ( -50, -10, -4, -3, -2, 0, 2, 3, 3, 3, 4, 5, 6, 7, 9, 13, 24, 25,
26, 27, 50, 49, 48, 60 );
print "@numbers\n";
$number_string = format_number_list( @numbers );
print "$number_string\n";
@numbers = expand_number_list( $number_string );
print "@numbers\n\n";

@numbers = ( 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 );
print "@numbers\n";
$number_string = format_number_list( @numbers );
print "$number_string\n";
@numbers = expand_number_list( $number_string );
print "@numbers\n\n";

@numbers = ( 11, 10, 9, 8, 9, 10, 11, 12, 11, 10, 9, 8, 'foo', 1, 2 );
print "@numbers\n";
$number_string = format_number_list( @numbers );
print "$number_string\n";
@numbers = expand_number_list( $number_string );
print "@numbers\n\n";

$number_string = '3-(-5)';
print "$number_string\n";
@numbers = expand_number_list( $number_string );
print "@numbers\n";

sub format_number_list
{
 my @numbers = @_;
 my @numbers_compressed;
 my $number_string = '';
 my $number_count = @numbers;
 unless( $number_count )
 {
  return $number_string;
 }
 my $start_number = 0;
 my $end_number = 0;
 while( $end_number < $number_count )
 {
  my $direction = 'none';
  for( my $count = $start_number + 1; $count < $number_count; $count++ )
  {
   if( $numbers[$count] == ( $numbers[$count - 1] + 1 ) )
   {
    if( $direction eq 'none' )
    {
     $direction = 'up';
     $end_number++;
    }
    elsif( $direction eq 'up' )
    {
     $end_number++;
    }
    else
    {
     last;
    }
   }
   elsif( $numbers[$count] == ( $numbers[$count - 1] - 1 ) )
   {
    if( $direction eq 'none' )
    {
     $direction = 'down';
     $end_number++;
    }
    elsif( $direction eq 'down' )
    {
     $end_number++;
    }
    else
    {
     last;
    }
   }
   else
   {
    last;
   }
  }
  if( $start_number == $end_number )
  {
   push( @numbers_compressed, ( $numbers[$start_number] >= 0 ?
$numbers[$start_number] : "$numbers[$start_number]" ) );
   $start_number++;
   $end_number++;
  }
  else
  {
   my $number_range_string = $numbers[$start_number] >= 0 ?
$numbers[$start_number] : "$numbers[$start_number]";
   $number_range_string .= '-';
   $number_range_string .= $numbers[$end_number] >= 0 ?
$numbers[$end_number] : "$numbers[$end_number]";
   push( @numbers_compressed, $number_range_string );
   $end_number++;
   $start_number = $end_number;
  }
 }
 $number_string = join( ', ', @numbers_compressed );
 return $number_string;
}

sub expand_number_list
{
 my $number_string = shift;
 my @parts = split( /,/, $number_string );
 my @numbers;
 foreach my $part ( @parts )
 {
  $part =~ s/\s+//g;
  if( $part =~ /[^(]-/ )
  {
   my ( $start_number, $end_number ) = split( /(?<=[^(])-/, $part );
   $start_number =~ s/[()]//g;
   $end_number =~ s/[()]//g;
   if( $start_number < $end_number )
   {
    for( my $count = $start_number; $count <= $end_number; $count++ )
    {
     push( @numbers, $count );
    }
   }
   else
   {
    for( my $count = $start_number; $count >= $end_number; $count-- )
    {
     push( @numbers, $count );
    }
   }
  }
  else
  {
   $part =~ s/[()]//g;
   push( @numbers, $part );
  }
 }
 return @numbers;
}

