【COBOL】文字列操作完全ガイド|STRING・UNSTRING・INSPECT・文字列関数の使い方

COBOLの文字列操作は、他の言語のように演算子(+や&)で連結するのではなく、STRING文・UNSTRING文・INSPECT文といった専用の命令を使います。最初は独特に感じますが、仕組みを理解するとバッチ処理や帳票出力で非常に強力に使えます。

この記事では、文字列の結合に使うSTRING文を基礎から解説し、分割のUNSTRING文、文字変換のINSPECT文、さらに現代COBOLの文字列関数まで体系的に説明します。CSV組み立てや日付整形などの実践コードも合わせて紹介します。

この記事でわかること

  • STRING文の構文と DELIMITED BY SIZE / DELIMITED BY 文字の違い
  • WITH POINTER で結合位置を制御する方法
  • ON OVERFLOW で桁あふれを検知する方法
  • UNSTRING文で文字列を分割する方法
  • INSPECT文で文字の置換・変換を行う方法
  • FUNCTION CONCATENATE / TRIM など現代COBOLの文字列関数
  • CSV組み立て・日付整形・ログ出力の実践パターン
スポンサーリンク

STRING文の基本構文

STRING文は複数の文字列を順番に結合して、1つの変数(受け取り領域)に書き込む命令です。

STRING文の基本構文
STRING 送り元1 [送り元2 ...] DELIMITED BY {SIZE | 区切り文字}
       [送り元3 [送り元4 ...] DELIMITED BY {SIZE | 区切り文字}]
       ...
       INTO 受け取り先
       [WITH POINTER ポインタ変数]
       [ON OVERFLOW 処理]
       [NOT ON OVERFLOW 処理]
END-STRING.
説明
DELIMITED BY SIZE 送り元のPIC句で定義した全桁をそのまま転送する(スペースも含む)
DELIMITED BY 文字 指定した文字(スペース等)が現れた位置で転送を打ち切る
INTO 受け取り先 結合結果を書き込む変数。事前にSPACESで初期化しておくのが定石
WITH POINTER 書き込み開始位置(1始まり)を変数で管理する。複数回のSTRINGで同一領域に追記できる
ON OVERFLOW 受け取り先の容量を超えた場合に実行する処理

DELIMITED BY SIZEとDELIMITED BY SPACEの違い

この2つの違いはCOBOL文字列操作で最初に理解すべき重要なポイントです。

DELIMITED BY SIZE と DELIMITED BY SPACE の比較
WORKING-STORAGE SECTION.
01 WS-FIRST        PIC X(10) VALUE 'TARO      '.  *> 後ろにスペース6文字
01 WS-LAST         PIC X(10) VALUE 'YAMADA    '.  *> 後ろにスペース4文字
01 WS-RESULT-A     PIC X(25) VALUE SPACES.
01 WS-RESULT-B     PIC X(25) VALUE SPACES.

PROCEDURE DIVISION.
    *--- DELIMITED BY SIZE: 全桁転送(スペースも含む)---
    STRING WS-FIRST DELIMITED BY SIZE
           ' '      DELIMITED BY SIZE   *> 区切り文字として半角スペース1文字
           WS-LAST  DELIMITED BY SIZE
           INTO WS-RESULT-A
    *> 結果: 'TARO       YAMADA    '(スペース込みで20文字+区切り1文字)

    *--- DELIMITED BY SPACE: 最初のスペースまでを転送 ---
    MOVE SPACES TO WS-RESULT-B
    STRING WS-FIRST DELIMITED BY SPACE   *> 'TARO'の4文字のみ(スペース手前まで)
           ' '      DELIMITED BY SIZE    *> 区切りスペース
           WS-LAST  DELIMITED BY SPACE   *> 'YAMADA'の6文字のみ
           INTO WS-RESULT-B
    *> 結果: 'TARO YAMADA             '(有効文字のみ)

    DISPLAY 'SIZE:  [' WS-RESULT-A ']'
    DISPLAY 'SPACE: [' WS-RESULT-B ']'
    STOP RUN.
使い分けの原則

  • DELIMITED BY SIZE: 数値編集項目・固定長コード(01, JP等)を結合するとき
  • DELIMITED BY SPACE: 可変長の文字データ(名前・住所等)を詰めて結合するとき
  • DELIMITED BY 文字: カンマやスラッシュなど特定の区切り文字まで転送するとき

WITH POINTERで書き込み位置を制御する

WITH POINTER句を使うと、書き込みの開始位置を指定できます。ループで繰り返しSTRINGを呼び出すときや、1つの大きな出力領域に複数回追記するときに使います。

WITH POINTERの使い方
WORKING-STORAGE SECTION.
01 WS-BUFFER       PIC X(80) VALUE SPACES.
01 WS-PTR          PIC 9(3) VALUE 1.     *> 書き込み開始位置(1から始まる)
01 WS-ITEM         PIC X(20).

PROCEDURE DIVISION.
    MOVE 1 TO WS-PTR

    *> 1回目: バッファ先頭から書き込み
    MOVE '2024-01-15' TO WS-ITEM
    STRING WS-ITEM DELIMITED BY SPACE
           INTO WS-BUFFER
           WITH POINTER WS-PTR
    *> WS-PTR = 11(10文字書き込んだので次の開始位置が11)

    *> 2回目: カンマ区切りを追加
    STRING ',' DELIMITED BY SIZE
           INTO WS-BUFFER
           WITH POINTER WS-PTR
    *> WS-PTR = 12

    *> 3回目: 次のデータを追記
    MOVE 'TANAKA JIRO' TO WS-ITEM
    STRING WS-ITEM DELIMITED BY SPACE
           INTO WS-BUFFER
           WITH POINTER WS-PTR

    DISPLAY WS-BUFFER.   *> '2024-01-15,TANAKA JIRO'
    STOP RUN.

ON OVERFLOW / NOT ON OVERFLOW

書き込み先の容量を超えた場合(ポインタが最大桁を越えた場合)、ON OVERFLOWが実行されます。

ON OVERFLOWで桁あふれを検知する
WORKING-STORAGE SECTION.
01 WS-OUT          PIC X(10) VALUE SPACES.
01 WS-A            PIC X(8)  VALUE 'ABCDEFGH'.
01 WS-B            PIC X(8)  VALUE 'IJKLMNOP'.
01 WS-OVERFLOW-FLG PIC X(1)  VALUE 'N'.

PROCEDURE DIVISION.
    STRING WS-A DELIMITED BY SIZE
           WS-B DELIMITED BY SIZE
           INTO WS-OUT
        ON OVERFLOW
            MOVE 'Y' TO WS-OVERFLOW-FLG
            DISPLAY '警告: 文字列が受け取り領域を超えました'
        NOT ON OVERFLOW
            DISPLAY '正常に結合しました'
    END-STRING

    IF WS-OVERFLOW-FLG = 'Y'
        *> WS-OUTは最初の10文字まで書き込まれている
        DISPLAY '実際の結果: [' WS-OUT ']'  *> 'ABCDEFGHIJ'(途中まで)
    END-IF.
注意: ON OVERFLOWは途中で止まらない
ON OVERFLOWが発生しても、書き込み先に収まる部分まではデータが書き込まれます。OVERFLOWは「書き込めなかった部分が発生した」という通知であり、全体を中断するわけではありません。受け取り先の桁数はあらかじめ十分に確保しておきましょう。

UNSTRING文で文字列を分割する

UNSTRING文はSTRINGの逆で、1つの文字列を指定した区切り文字で分割して複数の変数に振り分けます。CSVのパースや固定フォーマットからのフィールド抽出に使います。

UNSTRING文の基本構文
UNSTRING 送り元
    DELIMITED BY [ALL] 区切り文字 [OR [ALL] 区切り文字2 ...]
    INTO 受け取り1 [DELIMITER IN 区切り保存先1] [COUNT IN 文字数1]
         受け取り2 [DELIMITER IN 区切り保存先2] [COUNT IN 文字数2]
         ...
    [WITH POINTER ポインタ変数]
    [TALLYING IN カウンタ変数]
    [ON OVERFLOW 処理]
    [NOT ON OVERFLOW 処理]
END-UNSTRING.
CSVの1行をフィールドに分割する
WORKING-STORAGE SECTION.
01 WS-CSV-LINE     PIC X(60) VALUE '20240115,TANAKA JIRO,TOKYO,35'.
01 WS-DATE         PIC X(8).
01 WS-NAME         PIC X(20).
01 WS-CITY         PIC X(20).
01 WS-AGE          PIC X(3).
01 WS-FIELD-COUNT  PIC 9(2).

PROCEDURE DIVISION.
    MOVE SPACES TO WS-DATE WS-NAME WS-CITY WS-AGE
    MOVE 0 TO WS-FIELD-COUNT

    UNSTRING WS-CSV-LINE
        DELIMITED BY ','
        INTO WS-DATE
             WS-NAME
             WS-CITY
             WS-AGE
        TALLYING IN WS-FIELD-COUNT
    END-UNSTRING

    DISPLAY '日付: '   WS-DATE         *> '20240115'
    DISPLAY '氏名: '   WS-NAME         *> 'TANAKA JIRO'
    DISPLAY '都市: '   WS-CITY         *> 'TOKYO'
    DISPLAY '年齢: '   WS-AGE          *> '35'
    DISPLAY 'フィールド数: ' WS-FIELD-COUNT *> 4
    STOP RUN.
複数の区切り文字に対応(OR区切り)
WORKING-STORAGE SECTION.
01 WS-INPUT        PIC X(30) VALUE 'TOKYO/OSAKA NAGOYA,FUKUOKA'.
01 WS-CITY1        PIC X(10).
01 WS-CITY2        PIC X(10).
01 WS-CITY3        PIC X(10).
01 WS-CITY4        PIC X(10).

PROCEDURE DIVISION.
    UNSTRING WS-INPUT
        DELIMITED BY '/' OR SPACE OR ','   *> 3種類の区切りに対応
        INTO WS-CITY1 WS-CITY2 WS-CITY3 WS-CITY4
    END-UNSTRING

    DISPLAY WS-CITY1  *> 'TOKYO'
    DISPLAY WS-CITY2  *> 'OSAKA'
    DISPLAY WS-CITY3  *> 'NAGOYA'
    DISPLAY WS-CITY4  *> 'FUKUOKA'
DELIMITER IN でどの区切り文字で切れたかを取得する
WORKING-STORAGE SECTION.
01 WS-DATA         PIC X(30) VALUE 'APPLE,BANANA/CHERRY'.
01 WS-ITEM1        PIC X(10).
01 WS-ITEM2        PIC X(10).
01 WS-ITEM3        PIC X(10).
01 WS-DELIM1       PIC X(1).    *> ITEM1の後の区切り文字
01 WS-DELIM2       PIC X(1).    *> ITEM2の後の区切り文字

PROCEDURE DIVISION.
    UNSTRING WS-DATA
        DELIMITED BY ',' OR '/'
        INTO WS-ITEM1 DELIMITER IN WS-DELIM1
             WS-ITEM2 DELIMITER IN WS-DELIM2
             WS-ITEM3
    END-UNSTRING

    DISPLAY WS-ITEM1  WS-DELIM1  *> 'APPLE     ,'
    DISPLAY WS-ITEM2  WS-DELIM2  *> 'BANANA    /'
    DISPLAY WS-ITEM3             *> 'CHERRY'

INSPECT文で文字を置換・変換する

INSPECT文は文字列内を走査して文字をカウントしたり、特定の文字を別の文字に置き換えたりします。大文字・小文字変換や文字のサニタイズによく使われます。

書き方 用途
INSPECT … TALLYING 指定した文字の出現回数をカウントする
INSPECT … REPLACING 指定した文字を別の文字に置き換える
INSPECT … CONVERTING 文字の対応表で一括変換する(大小変換に便利)
INSPECT … TALLYING REPLACING カウントと置き換えを同時に行う
INSPECT CONVERTING で大文字→小文字変換
WORKING-STORAGE SECTION.
01 WS-TEXT         PIC X(30) VALUE 'Hello World COBOL 2024'.
01 WS-LOWER-A      PIC X(26) VALUE 'abcdefghijklmnopqrstuvwxyz'.
01 WS-UPPER-A      PIC X(26) VALUE 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.

PROCEDURE DIVISION.
    *> 小文字 → 大文字
    INSPECT WS-TEXT
        CONVERTING WS-LOWER-A TO WS-UPPER-A
    DISPLAY WS-TEXT    *> 'HELLO WORLD COBOL 2024'

    *> 大文字 → 小文字(逆向き)
    MOVE 'Hello World' TO WS-TEXT
    INSPECT WS-TEXT
        CONVERTING WS-UPPER-A TO WS-LOWER-A
    DISPLAY WS-TEXT    *> 'hello world'
INSPECT REPLACING で文字を一括置換
WORKING-STORAGE SECTION.
01 WS-PATH         PIC X(40) VALUE 'C:\COBOL\SOURCE\PROGRAM.CBL'.
01 WS-COUNT        PIC 9(3)  VALUE 0.

PROCEDURE DIVISION.
    *> バックスラッシュをスラッシュに置換(UNIX形式に変換)
    INSPECT WS-PATH
        REPLACING ALL '' BY '/'
    DISPLAY WS-PATH    *> 'C:/COBOL/SOURCE/PROGRAM.CBL'

    *> スペースをアンダースコアに置換
    MOVE 'TOKYO OSAKA NAGOYA' TO WS-PATH
    INSPECT WS-PATH
        REPLACING ALL SPACE BY '_'
    DISPLAY WS-PATH    *> 'TOKYO_OSAKA_NAGOYA'
INSPECT TALLYING で文字の出現回数をカウント
WORKING-STORAGE SECTION.
01 WS-CSV          PIC X(50) VALUE 'A001,B002,C003,D004,E005'.
01 WS-COMMA-CNT    PIC 9(3)  VALUE 0.

PROCEDURE DIVISION.
    INSPECT WS-CSV
        TALLYING WS-COMMA-CNT FOR ALL ','
    DISPLAY 'カンマの数: ' WS-COMMA-CNT   *> '4'
    *> フィールド数 = WS-COMMA-CNT + 1 = 5

現代COBOLの文字列関数(COBOL 2002以降)

COBOL 2002規格からINTRINSIC FUNCTION(組み込み関数)が整備され、文字列操作が大幅に簡潔に書けるようになりました。IBM Enterprise COBOLやGnuCOBOLでも使用できます。

関数 機能
FUNCTION CONCATENATE(str1 str2…) 複数の文字列を連結して返す
FUNCTION TRIM(str [LEADING|TRAILING]) 先頭・末尾のスペースを除去する
FUNCTION UPPER-CASE(str) 文字列を大文字に変換する
FUNCTION LOWER-CASE(str) 文字列を小文字に変換する
FUNCTION LENGTH(str) 文字列の長さ(バイト数)を返す
FUNCTION REVERSE(str) 文字列を逆順にして返す
FUNCTION SUBSTITUTE(str old new) strの中のoldをnewに置換して返す(COBOL 2023)
文字列関数の使用例
WORKING-STORAGE SECTION.
01 WS-FIRST        PIC X(10) VALUE 'TARO      '.
01 WS-LAST         PIC X(10) VALUE 'YAMADA    '.
01 WS-FULL-NAME    PIC X(30).
01 WS-TEXT         PIC X(20) VALUE '  HELLO WORLD  '.
01 WS-TRIMMED      PIC X(20).
01 WS-LEN          PIC 9(3).

PROCEDURE DIVISION.
    *--- FUNCTION CONCATENATE: 文字列を連結 ---
    MOVE FUNCTION CONCATENATE(
        FUNCTION TRIM(WS-LAST TRAILING)
        ' '
        FUNCTION TRIM(WS-FIRST TRAILING))
    TO WS-FULL-NAME
    DISPLAY WS-FULL-NAME   *> 'YAMADA TARO'

    *--- FUNCTION TRIM: スペース除去 ---
    MOVE FUNCTION TRIM(WS-TEXT) TO WS-TRIMMED
    DISPLAY '[' WS-TRIMMED ']'   *> '[HELLO WORLD]'

    *--- FUNCTION LENGTH: 文字列長 ---
    MOVE FUNCTION LENGTH(WS-TRIMMED) TO WS-LEN
    DISPLAY '長さ: ' WS-LEN

    *--- FUNCTION UPPER-CASE / LOWER-CASE ---
    DISPLAY FUNCTION UPPER-CASE('cobol 2024')  *> 'COBOL 2024'
    DISPLAY FUNCTION LOWER-CASE('COBOL 2024')  *> 'cobol 2024'

    STOP RUN.
FUNCTION TRIMの注意点
FUNCTION TRIM(変数 TRAILING) は末尾スペースを除去し、LEADING は先頭スペースを除去します。省略すると両端を除去します。ただし結果はアルファベット型の一時領域に返るため、PIC X定義の変数にMOVEするか、DISPLAY/STRINGに直接渡して使います。

文字列長の扱い方とスペースの問題

COBOLのPIC X定義は固定長です。文字が短い場合、右側にスペースが埋まります。文字列操作でスペース処理を正しく扱わないと意図しない結果になります。

有効長の取得と実用パターン
WORKING-STORAGE SECTION.
01 WS-NAME         PIC X(20) VALUE 'NAKAMURA'.   *> 後ろ12文字はスペース
01 WS-LEN          PIC 9(3).
01 WS-MSG          PIC X(40).

PROCEDURE DIVISION.
    *> PIC句の全桁数(定義上の長さ)
    MOVE FUNCTION LENGTH(WS-NAME) TO WS-LEN
    DISPLAY '全桁数: ' WS-LEN      *> '20'

    *> 有効文字数(末尾スペースを除いた長さ)
    MOVE FUNCTION LENGTH(FUNCTION TRIM(WS-NAME TRAILING)) TO WS-LEN
    DISPLAY '有効長: ' WS-LEN      *> '8'

    *> 旧来の方法(INSPECT TALLYINGで末尾スペース数を数えて引く)
    *> 現代COBOLではFUNCTION TRIMが簡潔でおすすめ

    *> メッセージ組み立て
    STRING '氏名: ' DELIMITED BY SIZE
           WS-NAME DELIMITED BY SPACE
           'さん' DELIMITED BY SIZE
           INTO WS-MSG
    DISPLAY WS-MSG    *> '氏名: NAKAMURAさん'

実践パターン4選

CSV行の組み立て(WITH POINTERで追記)

ループで複数フィールドをCSV形式に結合するパターンです。WITH POINTERで位置を管理しながら追記します。

CSVレコードの組み立て
WORKING-STORAGE SECTION.
01 WS-CSV-LINE     PIC X(200) VALUE SPACES.
01 WS-PTR          PIC 9(3)   VALUE 1.
01 WS-ORDER-DATE   PIC X(8)   VALUE '20240115'.
01 WS-CUST-ID      PIC X(10)  VALUE 'C00123'.
01 WS-ITEM-CODE    PIC X(8)   VALUE 'ITEM-001'.
01 WS-QTY          PIC 9(5)   VALUE 00010.
01 WS-AMOUNT       PIC 9(9)V99 VALUE 15000.00.
01 WS-AMT-EDIT     PIC ZZZ,ZZZ,ZZ9.99.  *> 編集項目

PROCEDURE DIVISION.
    MOVE 1 TO WS-PTR
    MOVE SPACES TO WS-CSV-LINE

    *> 日付
    STRING WS-ORDER-DATE DELIMITED BY SIZE
           ',' DELIMITED BY SIZE
           INTO WS-CSV-LINE WITH POINTER WS-PTR

    *> 顧客ID(末尾スペースを詰める)
    STRING WS-CUST-ID DELIMITED BY SPACE
           ',' DELIMITED BY SIZE
           INTO WS-CSV-LINE WITH POINTER WS-PTR

    *> 商品コード
    STRING WS-ITEM-CODE DELIMITED BY SPACE
           ',' DELIMITED BY SIZE
           INTO WS-CSV-LINE WITH POINTER WS-PTR

    *> 数量(数値を文字として)
    MOVE WS-QTY TO WS-AMT-EDIT
    STRING FUNCTION TRIM(WS-AMT-EDIT LEADING)
                    DELIMITED BY SIZE
           ',' DELIMITED BY SIZE
           INTO WS-CSV-LINE WITH POINTER WS-PTR

    *> 金額
    MOVE WS-AMOUNT TO WS-AMT-EDIT
    STRING FUNCTION TRIM(WS-AMT-EDIT LEADING)
                    DELIMITED BY SIZE
           INTO WS-CSV-LINE WITH POINTER WS-PTR

    DISPLAY WS-CSV-LINE   *> '20240115,C00123,ITEM-001,10,15,000.00'
    STOP RUN.

日付文字列の整形(YYYYMMDD → YYYY-MM-DD)

数値型の日付をハイフン区切りの文字列に変換するパターンです。

日付フォーマット変換
WORKING-STORAGE SECTION.
01 WS-DATE-NUM     PIC 9(8)  VALUE 20240115.
01 WS-DATE-CHAR    PIC X(8).
01 WS-DATE-FMT     PIC X(10).   *> YYYY-MM-DD
01 WS-YEAR         PIC X(4).
01 WS-MONTH        PIC X(2).
01 WS-DAY          PIC X(2).

PROCEDURE DIVISION.
    *> 数値日付を文字列に変換
    MOVE WS-DATE-NUM TO WS-DATE-CHAR

    *> 年・月・日に分割
    MOVE WS-DATE-CHAR(1:4) TO WS-YEAR
    MOVE WS-DATE-CHAR(5:2) TO WS-MONTH
    MOVE WS-DATE-CHAR(7:2) TO WS-DAY

    *> ハイフン区切りで結合
    STRING WS-YEAR  DELIMITED BY SIZE
           '-'      DELIMITED BY SIZE
           WS-MONTH DELIMITED BY SIZE
           '-'      DELIMITED BY SIZE
           WS-DAY   DELIMITED BY SIZE
           INTO WS-DATE-FMT

    DISPLAY WS-DATE-FMT   *> '2024-01-15'
    STOP RUN.

ログメッセージの組み立て

バッチ処理でよく使うタイムスタンプ付きログを組み立てるパターンです。

タイムスタンプ付きログ出力
WORKING-STORAGE SECTION.
01 WS-LOG-MSG      PIC X(100) VALUE SPACES.
01 WS-TIMESTAMP    PIC X(26).
01 WS-PROGRAM-ID   PIC X(8)   VALUE 'BATCHPGM'.
01 WS-MSG-BODY     PIC X(60).
01 WS-REC-COUNT    PIC 9(7)   VALUE 1234567.
01 WS-CNT-EDIT     PIC Z,ZZZ,ZZ9.

PERFORM LOG-OUTPUT
STOP RUN.

LOG-OUTPUT.
    *> 現在日時取得
    MOVE FUNCTION CURRENT-DATE TO WS-TIMESTAMP
    *> CURRENT-DATEの形式: YYYYMMDDHHMMSSXX(16文字)+ タイムゾーン

    *> カウントを編集
    MOVE WS-REC-COUNT TO WS-CNT-EDIT

    *> ログメッセージ組み立て
    STRING WS-TIMESTAMP(1:4) DELIMITED BY SIZE    *> YYYY
           '/'                DELIMITED BY SIZE
           WS-TIMESTAMP(5:2)  DELIMITED BY SIZE    *> MM
           '/'                DELIMITED BY SIZE
           WS-TIMESTAMP(7:2)  DELIMITED BY SIZE    *> DD
           ' '                DELIMITED BY SIZE
           WS-TIMESTAMP(9:2)  DELIMITED BY SIZE    *> HH
           ':'                DELIMITED BY SIZE
           WS-TIMESTAMP(11:2) DELIMITED BY SIZE    *> MM
           ':'                DELIMITED BY SIZE
           WS-TIMESTAMP(13:2) DELIMITED BY SIZE    *> SS
           ' ['               DELIMITED BY SIZE
           WS-PROGRAM-ID      DELIMITED BY SPACE
           '] 処理件数: '      DELIMITED BY SIZE
           WS-CNT-EDIT        DELIMITED BY SPACE
           '件'               DELIMITED BY SIZE
           INTO WS-LOG-MSG
    DISPLAY WS-LOG-MSG.
*> 出力例: '2024/01/15 10:30:45 [BATCHPGM] 処理件数: 1,234,567件'

ヘッダー項目を動的に組み立てる(STRING + MOVE)

帳票の見出し行を条件によって変えるパターンです。

帳票ヘッダーの動的組み立て
WORKING-STORAGE SECTION.
01 WS-HEADER       PIC X(60) VALUE SPACES.
01 WS-REPORT-DATE  PIC X(10).
01 WS-DEPT-NAME    PIC X(20).
01 WS-REPORT-TITLE PIC X(30).

PROCEDURE DIVISION.
    MOVE '2024-01-15' TO WS-REPORT-DATE
    MOVE 'システム部' TO WS-DEPT-NAME
    MOVE '月次売上集計レポート' TO WS-REPORT-TITLE

    STRING WS-REPORT-DATE DELIMITED BY SPACE
           ' 作成'         DELIMITED BY SIZE
           '  '            DELIMITED BY SIZE
           WS-DEPT-NAME   DELIMITED BY SPACE
           '  '            DELIMITED BY SIZE
           WS-REPORT-TITLE DELIMITED BY SPACE
           INTO WS-HEADER

    DISPLAY WS-HEADER
    *> '2024-01-15 作成  システム部  月次売上集計レポート'
    STOP RUN.

よくある落とし穴と対策

落とし穴 問題の内容 対策
受け取り先の初期化忘れ INTO変数を初期化しないと、前回の実行結果が残って文字化けが起きる STRINGの前に必ず MOVE SPACES TO 受け取り変数 で初期化する
DELIMITED BY SPACEで途中に空白がある文字列 “TANAKA JIRO” のような氏名をDELIMITED BY SPACEで渡すと”TANAKA”までしか転送されない 途中にスペースを含む文字列はDELIMITED BY SIZEで渡し、有効長をFUNCTION TRIMで管理する
WITH POINTERの初期化忘れ 2回目のSTRIN呼び出し時にWS-PTRを1に戻さないと、前回のPTR位置から書き込まれる 新しいメッセージを組み立てる前は必ずMOVE 1 TO WS-PTR(またはMOVE SPACES TO バッファ)を実行する
UNSTRING後のTALLYINGカウンタ TALLYINGはゼロ初期化されないため、ループ内でUNSTRINGを繰り返すと累積カウントになる UNSTRINGの前に MOVE 0 TO TALLYINGカウンタ で初期化する
数値のSTRING結合 PIC 9定義の数値を直接STRINGに渡すと、ゾーン10進数の内部コードが転送され文字化けする 数値はあらかじめ編集項目(PIC ZZZ9等)にMOVEして文字列化してからSTRINGに渡す
数値の文字列化(正しい方法)
WORKING-STORAGE SECTION.
01 WS-AMOUNT       PIC 9(7)V99  VALUE 12345.60.
01 WS-AMT-EDIT     PIC Z,ZZZ,ZZ9.99.    *> 編集用
01 WS-AMT-STR      PIC X(13).
01 WS-MSG          PIC X(30).

PROCEDURE DIVISION.
    *--- NG: 数値をそのままSTRINGに渡すと内部コードが転送される ---
    *STRING WS-AMOUNT DELIMITED BY SIZE INTO WS-MSG.   *> 文字化け

    *--- OK: 編集項目を経由して文字列化する ---
    MOVE WS-AMOUNT TO WS-AMT-EDIT          *> 12,345.60 という編集済み文字列になる
    MOVE WS-AMT-EDIT TO WS-AMT-STR         *> X型変数に格納

    STRING '金額: ' DELIMITED BY SIZE
           FUNCTION TRIM(WS-AMT-STR LEADING) DELIMITED BY SIZE
           '円' DELIMITED BY SIZE
           INTO WS-MSG
    DISPLAY WS-MSG   *> '金額: 12,345.60円'

よくある質問

QSTRING文でリテラル文字列(文字定数)を直接指定できますか?
Aはい、できます。STRING 'PREFIX-' DELIMITED BY SIZE … のようにシングルクォートで囲んだリテラルを直接USING句に書けます。定数として使う区切り文字や固定テキストをわざわざ変数に入れなくてよいので、コードが簡潔になります。
QSTRING文とMOVE文の使い分けは?
AMOVE文は1つの変数から別の1つの変数へデータを転送します。複数の変数を1つにまとめる場合や、末尾スペースを詰めて結合したい場合はSTRING文を使います。「1対1の転送→MOVE、複数を1つに→STRING」と覚えましょう。
QUNSTRING文で区切り文字が連続している場合(例: 「A,,C」のカンマ2個)はどうなりますか?
A連続した区切り文字の間は空(スペース)として扱われます。「A,,C」をカンマで分割すると、1つ目の受け取り変数に’A’、2つ目にスペース(空フィールド)、3つ目に’C’が入ります。ALL修飾子(DELIMITED BY ALL ‘,’)を使うと連続する区切りを1つとして扱い、空フィールドを飛ばします。
QFUNCTION CONCATENATEとSTRING文はどちらを使うべきですか?
A使用可能なCOBOLバージョンに依存します。COBOL 2002以降で新規開発するならFUNCTION CONCATENATEの方が直感的に書けます。ただし旧来の業務システム(メインフレーム等)では互換性のためにSTRING文が主流です。レガシーシステムの保守ではSTRING文を基本として、新機能追加ではFUNCTION系も検討するとよいでしょう。
QSTRING文でポインタが受け取り先の最大値を超えたらどうなりますか?
AON OVERFLOWが発生します。ポインタが受け取り先の桁数+1を超えた時点で書き込みは止まり、ON OVERFLOW句の処理が実行されます。収まった分のデータは書き込まれているので、桁が足りない場合に備えてON OVERFLOWを必ず記述する習慣をつけましょう。

まとめ

COBOLの文字列操作は専用命令が担当します。それぞれの役割をまとめます。

機能 説明
STRING文 複数の文字列を1つに結合する。DELIMITED BY SIZE/文字の使い分けが重要
WITH POINTER STRING文の書き込み位置を管理する。追記パターンに必須
ON OVERFLOW STRING文で受け取り先の容量超過を検知する
UNSTRING文 1つの文字列を区切り文字で分割して複数変数に振り分ける
INSPECT文 文字のカウント(TALLYING)・置換(REPLACING)・変換(CONVERTING)を行う
FUNCTION CONCATENATE COBOL 2002以降で使える文字列連結関数。TRIM/UPPER-CASE等も合わせて使う
数値の文字列化 数値型は編集項目(PIC ZZZ9等)を経由してから文字列操作に使う

文字列の初期化を忘れず、数値は編集項目を経由させるという2点を守るだけで、多くのバグを防げます。

COBOLのデータ転送の基本はMOVE文の完全ガイドで、画面への出力方法はDISPLAY文の使い方で解説しています。変数の初期化についてはINITIALIZE文のガイドも参照してください。