Task: Range expansion


C++: #include <iostream>
#include <sstream>
#include <iterator>
#include <climits>
#include <deque>








template<typename OutIter>
 bool parse_number_list_with_ranges(std::istream& is, OutIter out)
{
  int number;
  
  while (is >> number)
  {
    *out++ = number;

    char c;
    if (is >> c)
      switch(c)
      {
      case ',':
        continue;
      case '-':
        {
          int number2;
          if (is >> number2)
          {
            if (number2 < number)
              return false;
            while (number < number2)
              *out++ = ++number;
            char c2;
            if (is >> c2)
              if (c2 == ',')
                continue;
              else
                return false;
            else
              return is.eof();
          }
          else
            return false;
        }
      default:
        return is.eof();
      }
    else
      return is.eof();
  }
  
  
  return false;
}

int main()
{
  std::istringstream example("-6,-3--1,3-5,7-11,14,15,17-20");
  std::deque<int> v;
  bool success = parse_number_list_with_ranges(example, std::back_inserter(v));
  if (success)
  {
    std::copy(v.begin(), v.end()-1,
              std::ostream_iterator<int>(std::cout, ","));
    std::cout << v.back() << "\n";
  }
  else
    std::cout << "an error occured.";
}









Fortran:       MODULE HOMEONTHERANGE
       CONTAINS	
        CHARACTER*200 FUNCTION ERANGE(TEXT)	
Can't return a character value of variable size.
         CHARACTER*(*) TEXT	
         CHARACTER*200 ALINE	
         INTEGER N,N1,N2	
         INTEGER I,I1		
          ALINE = ""		
          L = 0			
          I = 1			
          CALL FORASIGN		
Chug through another number or number - number range.
        R:DO WHILE(EATINT(N1))	
            N2 = N1			
            IF (PASSBY("-")) CALL EATINT(N2)	
            IF (L.GT.0) CALL EMIT(",")		
            DO N = N1,N2,SIGN(+1,N2 - N1)	
              CALL SPLOT(N)				
              IF (N.NE.N2) CALL EMIT(",")		
            END DO				
            IF (.NOT.PASSBY(",")) EXIT R	
          END DO R		
Completed the scan. Just return the result.
          ERANGE = ALINE(1:L)	
         CONTAINS	
          SUBROUTINE FORASIGN	
    1       IF (I.LE.LEN(TEXT)) THEN	
              IF (TEXT(I:I).LE." ") THEN	
                I = I + 1				
                GO TO 1					
              END IF			
            END IF			
          END SUBROUTINE FORASIGN	

          LOGICAL FUNCTION PASSBY(C)	
Could consider or ignore case for letters, but this is really for single symbols.
           CHARACTER*1 C	
            PASSBY = .FALSE.	
            IF (I.LE.LEN(TEXT)) THEN	
              IF (TEXT(I:I).EQ.C) THEN	
                PASSBY = .TRUE.		
                I = I + 1		
                CALL FORASIGN		
              END IF		
            END IF		
          END FUNCTION PASSBY	

          LOGICAL FUNCTION EATINT(N)	
           INTEGER N	
           INTEGER D	
           LOGICAL NEG	
            EATINT = .FALSE.	
            IF (I.GT.LEN(TEXT)) RETURN	
            N = 0			
            IF (PASSBY("+")) THEN	
              NEG = .FALSE.		
             ELSE			
              NEG = PASSBY("-")		
            END IF			
            IF (I.GT.LEN(TEXT)) RETURN	
Chug through digits. Can develop -2147483648, thanks to the workings of two's complement.
   10       D = ICHAR(TEXT(I:I)) - ICHAR("0")	
            IF (0.LE.D .AND. D.LE.9) THEN	
              N = N*10 + D			
              I = I + 1				
              IF (I.LE.LEN(TEXT)) GO TO 10	
            END IF			
            IF (NEG) N = -N		
            EATINT = .TRUE.		
            CALL FORASIGN		
          END FUNCTION EATINT	

          SUBROUTINE EMIT(C)	
           CHARACTER*1 C	
            L = L + 1		
            IF (L.GT.LEN(ALINE)) STOP "Ran out of ALINE
            ALINE(L:L) = C	
          END SUBROUTINE EMIT	

          SUBROUTINE SPLOT(N)	
           INTEGER N		
           CHARACTER*12 FIELD	
           INTEGER I		
            WRITE (FIELD,"(I0)") N	
            DO I = 1,12		
              IF (FIELD(I:I).LE." ") EXIT	
              CALL EMIT(FIELD(I:I))	
            END DO		
          END SUBROUTINE SPLOT	
        END FUNCTION ERANGE	
      END MODULE HOMEONTHERANGE

      PROGRAM POKE
      USE HOMEONTHERANGE
      CHARACTER*(200) SOME
      SOME = "-6,-3--1,3-5,7-11,14,15,17-20"
      SOME = ERANGE(SOME)
      WRITE (6,*) SOME	
      END