SEPARATE

SEPARATE

operand1

SUBSTRING (operand1,operand2,operand3)
  [[STARTING] FROM [POSITION] operand8]  
  [LEFT [JUSTIFIED]] INTO operand4
 

IGNORE

 
  REMAINDER operand5
REMAINDER POSITION operand9
 

WITH [RETAINED]

[ANY] DELIMITERS
  INPUT DELIMITERS
  DELIMITERS   operand6
  [[GIVING] NUMBER  [INoperand7]

This document covers the following topics:

For an explanation 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


Function

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).

Syntax Description

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:

operand1 is the alphanumeric/binary constant or variable whose content is to be separated.

Trailing blanks in operand1 are removed before the value is processed (even if the blank is used as a delimiter character; see also the DELIMITERS option).

SUBSTRING
SUBSTRING Option:

Normally, the whole content of a field is separated, starting from the beginning of the field.

The SUBSTRING option allows you to separate only a certain part of the field. After the field name (operand1) in the SUBSTRING clause you specify first the starting position (operand2) and then the length (operand3) of the field portion to be separated. For example, if a field #A contained CONTRAPTION, SUBSTRING(#A,5,3) would contain RAP.

Note:
If you omit operand2, the starting position is assumed to be 1. If you omit operand3, the length is assumed to be from the starting position to the end of the field.

STARTING FROM POSITION operand8
STARTING FROM POSITION Option:

This option determines the starting position for the source operand (operand1) to be separated.

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:

operand4 represents the target operands. If an array is specified as target operand, it is filled occurrence by occurrence with the separated values.

The number of target operands corresponds to the number of delimiter characters (including trailing delimiter characters) in operand1, plus 1.

If operand4 is a dynamic variable, its length may be modified by the SEPARATE operation. The current length of a dynamic variable can be ascertained by using the system variable *LENGTH.

For general information on dynamic variables, see the section Using Dynamic and Large Variables.

IGNORE /

REMAINDER operand5

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:

  • IGNORE Option:

    If you specify IGNORE, Natural will ignore it if there are not enough target operands to receive the source value.

  • REMAINDER Option:

    If you specify REMAINDER operand5, that section of the source value which could not be placed into target operands will be placed into operand5. You may then use the content of operand5 for further processing, for example in a subsequent SEPARATE statement.

    REMAINDER can only be used for single-value source operands. For array source operands, use the REMAINDER POSITION option.

See also Rules and Operational Considerations and Example 3.

REMAINDER POSITION operand9
REMAINDER POSITION Option:

The value returned by the REMAINDER POSITION clause corresponds to the position from which a REMAINDER data field is filled.

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 RETAINED, however, each delimiter (that is, either default delimiters and blanks, or the delimiter specified with operand6) will also be placed into a target operand.

Example:

The following SEPARATE statement would place 150 into #B, + into #C, and 30 into #D:

...
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 operand7. The number actually obtained is the number of delimiters plus 1.

If you use the IGNORE Option, the maximum possible number returned in operand7 will be the number of target operands (operand4).

If you use the REMAINDER Option, the maximum possible number returned in operand7 will be the number of target operands (operand4) plus operand5.

DELIMITERS Option:

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 DELIMITERS option or specify WITH 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) is to be used as delimiter character.
WITH DELIMITERS operand6 Indicates that each of the characters specified in operand6 is to be treated as delimiter character.

If operand6 contains trailing blanks, these will be ignored.

Rules and Operational Considerations

Processing of Source and Target Operands

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.

Defining Ranges for STARTING FROM POSITION

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 #D (1:5) DYNAMIC with
*LENGTH(#D(*)) = (15,25,0,33,61)

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.

Values Returned by REMAINDER POSITION

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.

Overlapping Fields: REMAINDER 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.

Delimiters in SEPARATE

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.

Examples

Example 1 - Various Samples

** 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

Output of Program SEPEX1:

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 2 - Using an Array

** 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

Output of Program SEPEX2:

VALUE1,   VALUE2,VALUE3
                       
VALUE1                 
VALUE2                 
VALUE3                 
                       
                       
  3

Example 3 - Using REMAINDER/RETAINED Options

** 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

Output of Program SEPEX3:

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 4 - Using a Source Array of a Redefined String

**  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

Output of Program SEPEX4:

         #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 5 - Using a Source Array with RETAINED Delimiters

**  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

Output of Program SEPEX5:

       #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 6 - Using a Source Array with STARTING FROM and REMAINDER POSITION

**  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

Output of Program SEPEX6

#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