Thalecress
Thalecress

Reputation: 3451

Finding index of a substring in COBOL

I'm looking for the positions in a string where a specified substring occurs.

E.g, looking for substring "green" in the the string "green eggs and ham" should return me 1, but from "green eggs and green ham" would return me 1 and 14.

How should I do this?

Edit 1: Changed the wording so position starts at 1, not 0. Edit 2: I can find the first instance as WS-POINTER in the following snippet:

 MOVE 1 TO  WS-POINTER

 UNSTRING WS-STRING(1:WS-STRING-LEN)
  DELIMITED BY LT-MY-DELIMITER
  INTO WS-STRING-GARBAGE                             
  WITH POINTER WS-POINTER
 END-UNSTRING                   

Upvotes: 3

Views: 23930

Answers (3)

Bill Woodger
Bill Woodger

Reputation: 13076

MOVE 1 TO  WS-POINTER

UNSTRING WS-STRING(1:WS-STRING-LEN)
 DELIMITED BY LT-MY-DELIMITER
 INTO WS-STRING-GARBAGE                             
 WITH POINTER WS-POINTER
END-UNSTRING  

You ask about how to use the above for subsequent strings.

It is possible to use UNSTRING in two ways to get the counts you want. Either by having multiple receiving fields and COUNT-IN or by using multiple executions of UNSTRING using the POINTER value from the previous UNSTRING each time.

You need to account for the length of the delimiter. However, you will end up with "non-intuitive" code which will have to be "understood" each time someone picks up the program with it in.

Instead, it is a simple task with "substring" processing with either OCCURS DEPENDING ON or reference-modification (the method in the accepted answer).

You must make sure you don't "go beyond the end of the field" by ending the search when count + length-of-delimiter = max-length-of-string-to-search.

Upvotes: 0

Dennis
Dennis

Reputation: 1169

You could use QCLSCAN on IBM i

 77  QCLSCAN-SRCHLEN          PIC S9(3)     COMP-3.           
 77  QCLSCAN-STARTPOS         PIC S9(3)     COMP-3.           
 77  QCLSCAN-PATLEN           PIC S9(3)     COMP-3.           
 77  QCLSCAN-XLATE            PIC X(01)     VALUE "0".        
 77  QCLSCAN-TRIM             PIC X(01)     VALUE "0".        
 77  QCLSCAN-WILDCARD         PIC X(01)     VALUE LOW-VALUES. 
 77  QCLSCAN-FOUNDPOS         PIC S9(3)     COMP-3.           
 ...
 ...
     MOVE LENGTH OF WRK-ACCT-NBR TO QCLSCAN-SRCHLEN 
     MOVE     1                  TO QCLSCAN-STARTPOS
     MOVE     9                  TO QCLSCAN-PATLEN  
     MOVE "0"                    TO QCLSCAN-XLATE   
     MOVE "0"                    TO QCLSCAN-TRIM    
     MOVE "?"                    TO QCLSCAN-WILDCARD
     CALL "QCLSCAN" USING  WRK-ACCT-NBR             
                           QCLSCAN-SRCHLEN          
                           QCLSCAN-STARTPOS         
                           EMPLOYEE-SSN-9X          
                           QCLSCAN-PATLEN           
                           QCLSCAN-XLATE            
                           QCLSCAN-TRIM             
                           QCLSCAN-WILDCARD         
                           QCLSCAN-FOUNDPOS         
     IF QCLSCAN-FOUNDPOS > ZERO                     
* Found data in position QCLSCAN-FOUNDPOS
     ELSE
* Found no match
     END-IF

Upvotes: 0

Valdis Grinbergs
Valdis Grinbergs

Reputation: 46

AFAIK COBOL does not have a statement to find the position of a string within a string, so that needs to be done manually. However, COBOL does have a statement that counts the occurrences of a string within a string: INSPECT string TALLYING counter FOR ALL search-string

Here is an example program that works in OpenCOBOL (see OpenCobol.org):

   IDENTIFICATION DIVISION.
   PROGRAM-ID. OCCURRENCES.

   ENVIRONMENT DIVISION.
   INPUT-OUTPUT SECTION.
   FILE-CONTROL.

   DATA DIVISION.
   FILE SECTION.

   WORKING-STORAGE SECTION.
   01  TEST-STRING-1                    PIC X(30)
       VALUE 'green eggs and ham'.
   01  TEST-STRING-2                    PIC X(30)
       VALUE 'green eggs and green ham'.
   01  TEST-STRING                      PIC X(30).
   01  SEARCH-STRING                    PIC X(05)
       VALUE 'green'.
   01  MATCH-COUNT                      PIC 9.
   01  SEARCH-INDEX                     PIC 99.
   01  MATCH-POSITIONS.
       05  MATCH-POS                    PIC 99 OCCURS 9 TIMES.

   PROCEDURE DIVISION.
   MAIN.
       MOVE TEST-STRING-1 TO TEST-STRING
       PERFORM FIND-MATCHES

       MOVE TEST-STRING-2 TO TEST-STRING
       PERFORM FIND-MATCHES

       STOP RUN
       .

   FIND-MATCHES.
       MOVE ZERO TO MATCH-COUNT 
       INSPECT TEST-STRING TALLYING MATCH-COUNT
           FOR ALL SEARCH-STRING.
       DISPLAY 'FOUND ' MATCH-COUNT ' OCCURRENCE(S) OF '
           SEARCH-STRING ' IN:'
       DISPLAY TEST-STRING
       DISPLAY 'MATCHES FOUND AT POSITIONS: ' WITH NO ADVANCING
       PERFORM VARYING SEARCH-INDEX FROM 1 BY 1
           UNTIL SEARCH-INDEX = 30
           IF TEST-STRING (SEARCH-INDEX:5) = SEARCH-STRING
               DISPLAY SEARCH-INDEX ' ' WITH NO ADVANCING
       END-PERFORM
       DISPLAY ' '
       DISPLAY ' '
       .

Upvotes: 3

Related Questions