SEPARATE

#### Search Results

Search

# 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` [`IN`] operand7]

This document covers the following topics:

- Function

- Syntax Description

- Rules and Operational Considerations

- Examples

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 1 (for `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. The definition of delimiters may be modified using the `SCTAB` profile parameter.
`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 `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

- Defining Ranges for STARTING FROM POSITION

- Values Returned by REMAINDER POSITION

- Overlapping Fields: REMAINDER and REMAINDER POSITION

- Delimiters in SEPARATE

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

- Example 3 - Using REMAINDER/RETAINED Options

- Example 4 - Using a Source Array of a Redefined String

- Example 5 - Using a Source Array with RETAINED Delimiters

- Example 6 - Using a Source Array with STARTING FROM and REMAINDER POSITION

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

### On this page

- Function
- Syntax Description
- Rules and Operational Considerations
- Examples