Splitting text with UNSTRING
UNSTRING is the opposite of STRING: it splits one field into several
receiving fields at each delimiter.
IDENTIFICATION DIVISION.
PROGRAM-ID. UNSDEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-REC PIC X(40) VALUE "C00042;GRACE HOPPER;ARLINGTON".
01 WS-ID PIC X(6).
01 WS-NAME PIC X(20).
01 WS-CITY PIC X(15).
01 WS-NAME-LEN PIC 9(2).
01 WS-FIELDS PIC 9(2).
PROCEDURE DIVISION.
MOVE 0 TO WS-FIELDS
UNSTRING WS-REC DELIMITED BY ";"
INTO WS-ID
WS-NAME COUNT IN WS-NAME-LEN
WS-CITY
TALLYING IN WS-FIELDS
END-UNSTRING
DISPLAY "ID: [" WS-ID "]"
DISPLAY "NAME: [" WS-NAME "] " WS-NAME-LEN " CHARS"
DISPLAY "CITY: [" WS-CITY "]"
DISPLAY "FIELDS: " WS-FIELDS
STOP RUN.
Output:
ID: [C00042]
NAME: [GRACE HOPPER ] 12 CHARS
CITY: [ARLINGTON ]
FIELDS: 03
Each piece is moved into the next INTO field using normal MOVE rules:
padded with spaces, or truncated if it is too long.
The optional phrases:
| Phrase | Meaning |
|---|---|
COUNT IN n |
after a receiver: how many characters that piece had, before padding or truncation |
DELIMITER IN d |
after a receiver: which delimiter ended that piece |
TALLYING IN n |
once, at the end: adds the number of receivers filled to n |
WITH POINTER p |
start scanning at position p; updated as it goes |
ON OVERFLOW |
runs if there was text left over when the receivers ran out |
Because TALLYING adds to the counter, set it to zero first, just as the
example does with MOVE 0 TO WS-FIELDS.
Choosing delimiters
IDENTIFICATION DIVISION.
PROGRAM-ID. UNSALL.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-A PIC X(8).
01 WS-B PIC X(8).
01 WS-C PIC X(8).
01 WS-DAY PIC 9(2).
01 WS-MONTH PIC 9(2).
01 WS-YEAR PIC 9(4).
PROCEDURE DIVISION.
UNSTRING "RED GREEN BLUE" DELIMITED BY ALL SPACE
INTO WS-A WS-B WS-C
END-UNSTRING
DISPLAY "[" WS-A "][" WS-B "][" WS-C "]"
UNSTRING "7-3/2026" DELIMITED BY "/" OR "-"
INTO WS-DAY WS-MONTH WS-YEAR
END-UNSTRING
DISPLAY WS-YEAR WS-MONTH WS-DAY
MOVE "OLD" TO WS-C
UNSTRING "ONE,TWO" DELIMITED BY ","
INTO WS-A WS-B WS-C
END-UNSTRING
DISPLAY "[" WS-A "][" WS-B "][" WS-C "]"
UNSTRING "A,B,C,D" DELIMITED BY ","
INTO WS-A WS-B WS-C
ON OVERFLOW DISPLAY "MORE FIELDS THAN RECEIVERS"
END-UNSTRING
STOP RUN.
Output:
[RED ][GREEN ][BLUE ]
20260307
[ONE ][TWO ][OLD ]
MORE FIELDS THAN RECEIVERS
DELIMITED BY ALL SPACEtreats a run of spaces as one delimiter. WithoutALL, two spaces in a row would produce an empty field between them.ORlets several delimiters split the same text: here-and/.- A numeric receiver gets the piece as if it were moved from an
alphanumeric field, so
"7"intoPIC 9(2)becomes07. That is a handy way to turn7-3/2026into a proper date. - Receivers that get no data are not changed.
WS-Cstill saysOLDafter splittingONE,TWO. Clear your receivers first, or check the tally.
Leading delimiters
If the text starts with a delimiter, the first receiver gets an empty
piece, even with ALL. " RED GREEN" delimited by ALL SPACE puts
spaces in the first receiver and RED in the second. Trim the input
first (next lessons), or start with a pointer past the blanks.
On the job
UNSTRING is the workhorse for incoming delimited data: CSV extracts,
pipe-separated partner feeds, key=value parameter cards read at the
start of a batch job. The tally and ON OVERFLOW are your first line
of defence against a malformed record.
Your task
Dates keyed in by branch staff arrive as day, month and year separated
by / or -, with or without leading zeros: 4/9/2026, 24-12-2026,
1/1-2027. Convert each to ISO format YYYY-MM-DD.
Read lines until one says END. For each date, display either the ISO
date or, if it does not split into exactly three parts, the word
INVALID and the original text:
2026-09-04
2026-12-24
INVALID: 12/2026
You can assume each part that is present is numeric.