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