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