| SEPARATE | 
 | operand1 | 
 | |||
| 
                                                    SUBSTRING(operand1,operand2,operand3) | ||||||
| [[ STARTING]FROM[POSITION]
                                           operand8] | ||||||
| [ LEFT[JUSTIFIED]]INTOoperand4  | ||||||
| 
 | IGNORE | 
 | ||||
| REMAINDERoperand5 | ||||||
| REMAINDER POSITIONoperand9 | ||||||
| 
 | WITH[RETAINED] | 
 | [ ANY]DELIMITERS |  |   | |
| INPUT DELIMITERS | ||||||
| DELIMITERS operand6 | ||||||
| [[ GIVING]NUMBER[IN] operand7] | ||||||
This document covers the following topics:
For explanations of the symbols used in the syntax diagram, see Syntax Symbols.
Related Statements: COMPRESS |
                          COMPUTE |
                          EXAMINE |
                          MOVE |
                          MOVE ALL |
                          RESET
Belongs to Function Group: Arithmetic and Data Movement Operations
The SEPARATE statement is used to separate the content
                            of an alphanumeric or binary operand into two or more alphanumeric or binary
                            operands (or into multiple occurrences of an alphanumeric or binary array).
               
Operand Definition Table:
| Operand | Possible Structure | Possible Formats | Referencing Permitted | Dynamic Definition | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| operand1 | C | S | A | A | U | B | yes | no | ||||||||||||
| operand2 | C | S | N | P | I | B* | yes | no | ||||||||||||
| operand3 | C | S | N | P | I | B* | yes | no | ||||||||||||
| operand4 | S | A | G | A | U | B | yes | yes | ||||||||||||
| operand5 | S | A | U | B | yes | yes | ||||||||||||||
| operand6 | C | S | A | U | B | yes | no | |||||||||||||
| operand7 | S | N | P | I | yes | yes | ||||||||||||||
| operand8 | C | S | N | P | I | yes | no | |||||||||||||
| operand9 | S | N | P | I | yes | yes | ||||||||||||||
* Format B of
                            operand2 and
                            operand3 may be used only with a length
                            of less than or equal to 4.
               
Syntax Element Description:
| Syntax Element | Description | 
|---|---|
| operand1 |  Source Operand:    Trailing blanks in
                                                   | 
| SUBSTRING | SUBSTRING Option: Normally, the whole content of a field is separated, starting from the beginning of the field. The  Note: | 
| STARTING FROM POSITION
                                                operand8 | STARTING FROM POSITION
                                                     Option:  This option determines the starting position for the
                                                  source operand ( For details, see Defining Ranges for STARTING POSITION. | 
| LEFT JUSTIFIED | LEFT JUSTIFIED Option: This option causes leading blanks which may occur between the delimiter character and the next non-blank character to be removed from the target operand. | 
| operand4 |  Target Operand:    The number of target operands corresponds to the number of
                                                  delimiter characters (including trailing delimiter characters) in
                                                   If  For general information on dynamic variables, see the section Using Dynamic and Large Variables. | 
| IGNORE/ | IGNORE / REMAINDER Options: If you do not specify enough target fields for the source value to be separated into, you will receive an appropriate error message. To avoid this, you have two options: 
 See also Rules and Operational Considerations and Example 3. | 
| REMAINDER POSITION
                                                operand9 | REMAINDER POSITION Option: The value returned by the  For details, see Rules and Operational Considerations. | 
| DELIMITERS | DELIMITERS Option: See DELIMITERS Option below. | 
| RETAINED | RETAINED Option: Normally, the delimiter characters themselves are not moved into the target operands. When you specify  Example: The following  ... MOVE '150+30' TO #A SEPARATE #A INTO #B #C #D WITH RETAINED DELIMITER '+' ... See also Example 3. | 
| GIVING NUMBER
                                                operand7 | GIVING NUMBER Option: This option causes the number of filled target operands
                                                  (including those filled with blanks) to be returned in
                                                   If you use the IGNORE Option, the
                                                  maximum possible number returned in
                                                   If you use the REMAINDER Option, the
                                                  maximum possible number returned in
                                                   | 
Delimiter characters within operand1
                            indicate the positions at which the value is to be separated.
               
Syntax Element Description:
| Syntax Element | Description | 
|---|---|
| WITH [ANY]
                                                DELIMITERS | If you omit the DELIMITERSoption or specifyWITH ANY DELIMITERS, a blank and any character
                                             which is neither a letter nor a numeric character will be treated as delimiter
                                             character. | 
| WITH INPUT
                                                DELIMITERS | Indicates that the blank and the default
                                             input delimiter character (as specified with the session parameter ID) are to be
                                             used as delimiter character. | 
| WITH
                                                DELIMITERS operand6 | Indicates that each of the characters
                                             specified in operand6is to be treated
                                             as delimiter character. If  | 
Trailing blanks are ignored in source operands (in single values
                              and array occurrences as well) when the separation process starts. Trailing
                              blanks only count when the REMAINDER POSITION value is calculated:
                              see also Values Returned
                                 by REMAINDER POSITION.
               
If the source operand
                              (operand1) is an empty dynamic field
                              (*LENGTH=0) or an X-array that is not expanded, the
                              SEPARATE statement stops executing after resetting the following
                              fields:
               
all target operands
                                        (operand4);
                     
 the field (operand7)
                                        returning the number of filled target operands;
                     
 the REMAINDER data field
                                        (operand5);
                     
 the REMAINDER POSITION field
                                        (operand9)
                     
The same applies if the source operand contains only blanks.
The value range allowed for the STARTING FROM
                                 POSITION clause operand8 is
                              1:n where
                              n is the last byte of the source field.
                              
               
If the source operand
                              (operand1) is an array, all occurrences
                              are counted, including trailing blanks. For a dynamic array, the length of each
                              individual field is counted, up to the specified position.
               
Examples of operand8:
               
| Position 63 in #A
                                                  (A100) | is the 63rd char in #A. | 
| Position 63 in #B
                                                  (A20/1:10) | is the 3rd char in #B(4). | 
| Position 63 in #C
                                                  (A10/1:3,1:4) | is the 3rd char in #C(2,3). | 
|  
                                                    Position 63 in  | is the 23rd char in #D(4). | 
If you specify an invalid range (a negative or zero value, or a
                              value greater than the actual field length), the return fields listed in
                              Processing of Source and
                                 Target Operands are reset, but no runtime error occurs.
                              Since the STARTING FROM value denotes a position (and not an
                              offset), operand8 requires a minimum
                              value of 1 for the first execution.
               
The value returned by the REMAINDER POSITION clause
                              corresponds to the position from which a REMAINDER data field is
                              filled. 
               
Example:
... SEPARATE 'AB CD' INTO #A REMAINDER #R ...
The above statement returns #A= 'AB' and #R= '
                                 CD' as the REMAINDER starts after the separator character
                              (here: a blank), right after AB. With the REMAINDER
                                 POSITION option used instead, a value of 4 would be
                              returned.
               
Although trailing blanks are ignored during the separation
                              process, they are taken into account for the calculation of the REMAINDER
                                 POSITION value in occurrences of a source array.
               
 If all source segments are processed and the end of the source
                              field is reached, REMAINDER POSITION returns a value of zero
                              indicating "no more data". 
               
See also Example 6 - Using a Source Array with STARTING FROM and REMAINDER POSITION.
 When the SEPARATE statement is executed, the source
                              data (operand1) is usually copied and
                              processed from a work field. Therefore, the REMAINDER result is
                              independent of possibly overlapping source and result fields.
               
Such field backup copies are not produced if a REMAINDER
                                 POSITION clause is used. The complete separation process operates on the
                              original source operand, regardless of whether you separate the source and
                              target operands. Overlapping operands are neither rejected during compilation
                              nor execution but can cause undesired results.
               
When you separate a single-value field, the field border always delimits the last word. The same applies to each occurrence of an array field.
If the RETAINED DELIMITERS option is used, delimiters
                              are also placed into the target field. This only applies to delimiter
                              characters within an array occurrence, and not to consecutive array occurrences
                              that are automatically delimited (without delimiter character) when an
                              occurrence ends.
               
See also Example 4 - Using a Source Array of a Redefined String and Example 5 - Using a Source Array with RETAINED Delimiters.
** Example 'SEPEX1': SEPARATE                                           
************************************************************************
DEFINE DATA LOCAL                                                       
1 #TEXT1   (A6) INIT <'AAABBB'>                                         
1 #TEXT2   (A7) INIT <'AAA BBB'>                                        
1 #TEXT3   (A7) INIT <'AAA-BBB'>                                        
1 #TEXT4   (A7) INIT <'A.B/C,D'>                                        
1 #FIELD1A (A6)                                                         
1 #FIELD1B (A6)                                                         
1 #FIELD2A (A3)                                                         
1 #FIELD2B (A3)                                                         
1 #FIELD3A (A3)                                                         
1 #FIELD3B (A3)                                                         
1 #FIELD4A (A3)                                                         
1 #FIELD4B (A3)                                                         
1 #FIELD4C (A3)                                                         
1 #FIELD4D (A3)                                                         
1 #NBT     (N1)                                                         
1 #DEL     (A5)                                                         
END-DEFINE                                                        
*                                                                 
WRITE NOTITLE 'EXAMPLE A (SOURCE HAS NO BLANKS)'                  
SEPARATE #TEXT1 INTO #FIELD1A #FIELD1B GIVING NUMBER #NBT   
WRITE     / '=' #TEXT1 5X '=' #FIELD1A 4X '=' #FIELD1B 4X '=' #NBT
*                                                                 
WRITE NOTITLE /// 'EXAMPLE B (SOURCE HAS EMBEDDED BLANK)'         
SEPARATE #TEXT2 INTO #FIELD2A #FIELD2B GIVING NUMBER #NBT     
WRITE     / '=' #TEXT2 4X '=' #FIELD2A 7X '=' #FIELD2B 7X '=' #NBT
*                                                                 
WRITE NOTITLE /// 'EXAMPLE C (USING DELIMITER ''-'')'             
SEPARATE #TEXT3 INTO #FIELD3A #FIELD3B WITH DELIMITER '-'     
WRITE     /    '=' #TEXT3 4X '=' #FIELD3A 7X '=' #FIELD3B         
*                                                                 
MOVE ',/' TO #DEL                                                 
WRITE NOTITLE /// 'EXAMPLE D USING DELIMITER' '=' #DEL            
*                                                                 
SEPARATE #TEXT4 INTO #FIELD4A #FIELD4B                            
         #FIELD4C #FIELD4D WITH DELIMITER #DEL               
WRITE     /    '=' #TEXT4 4X '=' #FIELD4A 7X '=' #FIELD4B
          /              19X '=' #FIELD4C 7X '=' #FIELD4D
*                                                        
END 
                         EXAMPLE A (SOURCE HAS NO BLANKS)                                   
                                                                   
#TEXT1: AAABBB     #FIELD1A: AAABBB    #FIELD1B:           #NBT:  1
                                                                   
                                                                   
                                                                   
EXAMPLE B (SOURCE HAS EMBEDDED BLANK)                              
                                                                   
#TEXT2: AAA BBB    #FIELD2A: AAA       #FIELD2B: BBB       #NBT:  2
                                                                   
                                                                   
                                                                   
EXAMPLE C (USING DELIMITER '-')                                    
                                                                   
#TEXT3: AAA-BBB    #FIELD3A: AAA       #FIELD3B: BBB               
                                                                   
                                                                   
                                                                   
EXAMPLE D USING DELIMITER #DEL: ,/                                 
                                                                   
#TEXT4: A.B/C,D    #FIELD4A: A.B       #FIELD4B: C                 
                   #FIELD4C: D         #FIELD4D: 
                        
                       
               ** Example 'SEPEX2': SEPARATE (using array variable)                    
************************************************************************
DEFINE DATA LOCAL                                                       
1 #INPUT-LINE (A60) INIT <'VALUE1,   VALUE2,VALUE3'>                    
1 #FIELD      (A20/1:5)                                                 
1 #NUMBER     (N2)                                                      
END-DEFINE                                                              
*                                                                       
SEPARATE #INPUT-LINE LEFT JUSTIFIED INTO #FIELD (1:5)                   
                     GIVING NUMBER IN #NUMBER                      
*                                                                       
WRITE NOTITLE #INPUT-LINE //                                            
              #FIELD (1)  /                                             
              #FIELD (2)  /                                             
              #FIELD (3)  /                                             
              #FIELD (4)  /                                             
              #FIELD (5)  /                                             
              #NUMBER                                                   
*                                                                       
END 
                         VALUE1,   VALUE2,VALUE3
                       
VALUE1                 
VALUE2                 
VALUE3                 
                       
                       
  3 
                        
                       
               ** Example 'SEPEX3': SEPARATE (with REMAINDER, RETAIN option)           
************************************************************************
DEFINE DATA LOCAL                                                       
1 #INPUT-LINE (A60) INIT <'VAL1,   VAL2, VAL3,VAL4'>                    
1 #FIELD      (A10/1:4)                                                 
1 #REM        (A30)                                                     
END-DEFINE                                                              
*                                                                       
WRITE TITLE LEFT 'INP:' #INPUT-LINE /                                   
            '#FIELD (1)' 13T '#FIELD (2)' 25T '#FIELD (3)'              
        37T '#FIELD (4)' 49T 'REMAINDER'                                
       /    '----------' 13T '----------' 25T '----------'              
        37T '----------' 49T '------------------------------'           
*                                                                       
SEPARATE #INPUT-LINE INTO #FIELD (1:2)                                  
         REMAINDER #REM WITH DELIMITERS ','                        
WRITE #FIELD(1) 13T #FIELD(2) 25T #FIELD(3) 37T #FIELD(4) 49T #REM      
*                                                                       
RESET #FIELD(*) #REM                                                    
SEPARATE #INPUT-LINE INTO #FIELD (1:2)                            
         IGNORE WITH DELIMITERS ','                     
WRITE #FIELD(1) 13T #FIELD(2) 25T #FIELD(3) 37T #FIELD(4) 49T #REM
*                                                                 
RESET #FIELD(*) #REM                                              
SEPARATE #INPUT-LINE INTO #FIELD (1:4) IGNORE                     
        WITH RETAINED DELIMITERS ','                      
WRITE #FIELD(1) 13T #FIELD(2) 25T #FIELD(3) 37T #FIELD(4) 49T #REM
*                                                                 
RESET #FIELD(*) #REM                                              
*                                                                 
SEPARATE SUBSTRING(#INPUT-LINE,1,50) INTO #FIELD (1:4)            
         IGNORE WITH DELIMITERS ','                        
WRITE #FIELD(1) 13T #FIELD(2) 25T #FIELD(3) 37T #FIELD(4) 49T #REM
*                                                                 
END 
                         INP: VAL1, VAL2, VAL3,VAL4 #FIELD (1) #FIELD (2) #FIELD (3) #FIELD (4) REMAINDER ---------- ---------- ---------- ---------- ------------------------------ VAL1 VAL2 VAL3,VAL4 VAL1 VAL2 VAL1 , VAL2 , VAL1 VAL2 VAL3 VAL4
** Example 'SEPEX4': SEPARATE with source array ************************************************************************ * This example shows different results when separating a scalar string * or a string array redefining the scalar string. * * ************************************************************************ * * DEFINE DATA LOCAL 1 #TEXT (A24) INIT <'VAL1 VAL2 VAL3 VAL4 VAL5'> 1 REDEFINE #TEXT 2 #TEXTARRAY (A12/2) 1 #WORD1(A5/6) 1 #WORD2(A5/6) END-DEFINE * SEPARATE #TEXT INTO #WORD1(*) /* Redefinition may split original words into two parts SEPARATE #TEXTARRAY(*) INTO #WORD2(*) * DISPLAY #TEXT #WORD1(*) #TEXTARRAY(*) #WORD2(*) END
         #TEXT           #WORD1  #TEXTARRAY  #WORD2
------------------------ ------ ------------ ------
                                                   
VAL1 VAL2 VAL3 VAL4 VAL5 VAL1   VAL1 VAL2 VA VAL1  
                         VAL2   L3 VAL4 VAL5 VAL2  
                         VAL3                VA    
                         VAL4                L3    
                         VAL5                VAL4  
                                             VAL5 
                        
                       
               **  Example 'SEPEX5': SEPARATE with and without RETAINED DELIMITERS     
***********************************************************************
* This example shows different results with a source array             
* when using the option RETAINED DELIMITERS or not.                    
*                                                                      
*                                                                      
***********************************************************************
*                                                                      
*                                                                      
DEFINE DATA LOCAL                                                      
1 #TEXT(A20)        INIT <'VAL1,VAL2,VAL3,VAL4'>                       
1 #TEXTARRAY(A10/3) INIT <'VAL1,VAL2',                                 
                          'VAL3',                                      
                          'VAL4'>                                      
1 #WORD1(A5/7)                                                         
1 #WORD2(A5/7)                                                         
END-DEFINE                                                             
*                                                                      
SEPARATE #TEXT         INTO #WORD1(*)                                  
SEPARATE #TEXTARRAY(*) INTO #WORD2(*)                                  
DISPLAY #TEXT #WORD1(*) #TEXTARRAY(*) #WORD2(*)                        
*                                                                      
SEPARATE #TEXT         INTO #WORD1(*) WITH RETAINED DELIMITERS         
SEPARATE #TEXTARRAY(*) INTO #WORD2(*) WITH RETAINED DELIMITERS         
DISPLAY #TEXT #WORD1(*) #TEXTARRAY(*) #WORD2(*)                        
*                                                                      
END 
                                #TEXT         #WORD1 #TEXTARRAY #WORD2
-------------------- ------ ---------- ------
                                             
VAL1,VAL2,VAL3,VAL4  VAL1   VAL1,VAL2  VAL1  
                     VAL2   VAL3       VAL2  
                     VAL3   VAL4       VAL3  
                     VAL4              VAL4  
                                             
                                             
                                             
VAL1,VAL2,VAL3,VAL4  VAL1   VAL1,VAL2  VAL1  
                     ,      VAL3       ,     
                     VAL2   VAL4       VAL2  
                     ,                 VAL3  
                     VAL3              VAL4  
                     ,                       
                     VAL4 
                        
                       
               **  Example 'SEPEX6': SEPARATE with STARTING FROM and REMAINDER POSITION 
************************************************************************
* This example shows how the options STARTING FROM POSITION and         
* REMAINDER POSITION work together in a processing loop when            
* separating a source array.                                            
*                                                                       
************************************************************************
*                                                                       
*                                                                       
DEFINE DATA LOCAL                                                       
1 #TEXT (A15/1:3) INIT <'VAL1 VAL2',                                    
                        'VAL3',                                         
                        'VAL4 VAL5 VAL6'>                               
1 #WORD (A5/1:4)                                                        
1 #POS  (I1) INIT <1>                                                   
END-DEFINE                                                              
*                                                                       
WRITE '#TEXT(A15/1:3):      (1)             (2)             (3)'        
  /  16T #TEXT(*)                                                       
  /  16T '----+----1----+ ----2----+----3 ----+----4----+'              
  // '#WORD (A5/1:4): (1)   (2)   (3)   (4)      :  #POS'               
     '(within #TEXT(*))'                                                
*                                                                       
REPEAT                                                                  
  SEPARATE #TEXT(*) STARTING FROM POSITION #POS                         
      INTO #WORD(*) REMAINDER POSITION #POS                             
  WRITE 16T #WORD(*) 44T ': ' #POS
  UNTIL #POS = 0
END-REPEAT      
END 
                         #TEXT(A15/1:3):      (1)             (2)             (3)            
               VAL1 VAL2       VAL3            VAL4 VAL5 VAL6       
               ----+----1----+ ----2----+----3 ----+----4----+      
                                                                    
#WORD (A5/1:4): (1)   (2)   (3)   (4)      :  #POS (within #TEXT(*))
               VAL1  VAL2  VAL3  VAL4      :    36                  
               VAL5  VAL6                  :     0