Building text with STRING
STRING joins several pieces of text into one field. Each piece says how
much of it to use with a DELIMITED BY phrase:
IDENTIFICATION DIVISION.
PROGRAM-ID. STRDEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-FIRST PIC X(10) VALUE "GRACE".
01 WS-LAST PIC X(10) VALUE "HOPPER".
01 WS-FULL PIC X(30).
PROCEDURE DIVISION.
MOVE SPACES TO WS-FULL
STRING WS-LAST DELIMITED BY SPACE
", " DELIMITED BY SIZE
WS-FIRST DELIMITED BY SPACE
INTO WS-FULL
END-STRING
DISPLAY "[" WS-FULL "]"
STOP RUN.
Output:
[HOPPER, GRACE ]
DELIMITED BY SIZEcopies the whole item, trailing spaces and all.DELIMITED BY SPACEcopies up to (not including) the first space. That is how you drop the padding from a fixed-width field.DELIMITED BYany literal or data item stops at that text.
If the delimiter never appears, the whole item is copied.
STRING does not clear the target
STRING writes only the bytes it transfers. Whatever was in the rest of the
receiving field stays there. Forget the MOVE SPACES and you get this:
IDENTIFICATION DIVISION.
PROGRAM-ID. STRDIRTY.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-OUT PIC X(12) VALUE "XXXXXXXXXXXX".
PROCEDURE DIVISION.
STRING "ABC" DELIMITED BY SIZE INTO WS-OUT
DISPLAY "[" WS-OUT "]"
STOP RUN.
Output: [ABCXXXXXXXXX]. Always initialise the target first.
Names with spaces in them
DELIMITED BY SPACE breaks on VAN DYKE or NEW YORK: you get VAN.
The usual fix is to delimit by two spaces, DELIMITED BY " ". A
single space inside the value is kept, while the run of padding after it
ends the copy. (A value that fills its field completely has no padding,
and is simply copied whole.)
WITH POINTER
A pointer is a numeric field holding the next position to write in the target. STRING starts there and leaves it pointing just past the last byte written. That lets you build a field in several steps, and it tells you how long the result is:
IDENTIFICATION DIVISION.
PROGRAM-ID. STRPTR.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-LINE PIC X(30).
01 WS-PTR PIC 9(2).
PROCEDURE DIVISION.
MOVE SPACES TO WS-LINE
MOVE 1 TO WS-PTR
STRING "ACCT " DELIMITED BY SIZE
INTO WS-LINE WITH POINTER WS-PTR
STRING "00123" DELIMITED BY SIZE
INTO WS-LINE WITH POINTER WS-PTR
DISPLAY "[" WS-LINE "] NEXT: " WS-PTR
STOP RUN.
Output: [ACCT 00123 ] NEXT: 11. Ten bytes were written,
so the pointer is 11. The length of what you built is pointer - 1.
ON OVERFLOW
If the pieces do not fit, STRING stops at the end of the target and the
rest is lost. Add ON OVERFLOW to find out:
STRING ... INTO WS-SHORT
ON OVERFLOW DISPLAY "NAME TRUNCATED"
END-STRING
On the job
STRING shows up wherever a program produces text for humans or other
systems: names on statements, address lines, email bodies, CSV
extracts. Reviewers look for two things: a MOVE SPACES (or
INITIALIZE) before it, and an ON OVERFLOW wherever the data could be
longer than expected.
Your task
The customer letters program needs a one-line name and address label. Read three lines from input into the fields the starter declares:
- First name (
WS-FIRST,PIC X(15)) - Last name (
WS-LAST,PIC X(20)) - City (
WS-CITY,PIC X(15))
Build the label in WS-LABEL with a single STRING statement using
WITH POINTER, then display it, followed by its length (pointer - 1):
LABEL: HOPPER, GRACE (ARLINGTON)
LENGTH: 25
Last names and cities can contain a single space, such as VAN DYKE or
NEW YORK, and must come out whole.