Compaq COBOL
User Manual


Previous Contents Index

5.3.4 Examining the INSPECT Operation

Regardless of the type of inspection (TALLYING or REPLACING), the INSPECT statement has only one method for inspecting the characters in the item. This section analyzes the INSPECT statement and describes this inspection method.

Figure 5-3 shows an example of the INSPECT statement. The item to be inspected must be named (FIELD1 in our example), and the item name must be followed by a TALLYING phrase (TALLYING TLY). The TALLY phrase must be followed by one or more identifiers or literals (B). These identifiers or literals comprise the arguments. More than one argument makes up the argument list.

Figure 5-3 Sample INSPECT Statement


Each argument in an argument list can have other items associated with it. Thus, each argument that is used in a TALLYING operation must have a tally counter (such as TLY in the example) associated with it. The tally counter is incremented each time it matches the argument with a character or group of characters in the item being inspected.

Each argument in an argument list used in a REPLACING operation must have a replacement item associated with it. The compiler generates code that uses the replacement item to replace each string of characters in the item that matches the argument. Figure 5-4 shows a typical REPLACING phrase (with $ as the replacement item).

Figure 5-4 Typical REPLACING Phrase


Each argument in an argument list used with either a TALLYING or REPLACING operation can have a delimiter item (BEFORE/AFTER phrase) associated with it. If the delimiter item is not present, the argument is applied to the entire item. If the delimiter item is present, the argument is applied only to that portion of the item specified by the BEFORE/AFTER phrase.

5.3.4.1 Setting the Scanner

The INSPECT operation begins by setting the scanner to the leftmost character position of the item being inspected. It remains on this character until an argument has been matched with a character (or characters) or until all arguments have failed to find a match at that position.

5.3.4.2 Active/Inactive Arguments

When an argument has a BEFORE/AFTER phrase associated with it, that argument has a delimiter and may not be eligible to participate in a comparison at every position of the scanner. Thus, each argument in the argument list has an active/inactive status at any given setting of the scanner.

For example, an argument that has an AFTER phrase associated with it starts the INSPECT operation in an inactive state. The delimiter of the AFTER phrase must find a match before the argument can participate in the comparison. When the delimiter finds a match, the compiler generates code that retains the character position beyond the matched character string; then, when the scanner reaches or passes this position, the argument becomes active. This is shown in the following example:


INSPECT FIELD1 TALLYING TLY 
        FOR ALL "B" AFTER "X". 

If FIELD1 has a value of ABABXZBA, the argument B remains inactive until the scanner finds a match for delimiter X. Thus, argument B remains inactive while the compiler generates code that scans character positions 1 to 5. At character position 5, delimiter X finds a match, and because the character position beyond the matched delimiter character is the point at which the argument becomes active, argument B is compared for the first time at character position 6. It finds a successful match at character position 7, causing TLY to be incremented by 1.

Table 5-11 shows an INSPECT...TALLYING statement that is scanning FIELD1, tallying in TLY, and looking for the arguments and delimiters listed in the left column. Assume that TLY is initialized to 0.

Table 5-11 Relationship Among INSPECT Argument, Delimiter, Item Value, and Argument Active Position
Argument and
Delimiter
FIELD1
Value
Argument
Active at
Position
Contents of
TLY After Scan
ALL BXBXXXXBB 6 2
"B" AFTER "XX" XXXXXXXX 3 0
  BXBXBBBBXX never 0
       
  BXBXXBXXB 6 2
"X" AFTER "XX" XXXXXXXX 3 6
  BBBBBBXX never 0
       
  BXYBXBXX 7 0
"B" AFTER "XB" XBXBXBXB 3 3
  BBBBBBXB never 0
       
  XXXXBXXXX 6 0
"BX" AFTER "XB" XXXXBBXXX 6 1
  XXBXXXXBX 4 1

When an argument has an associated BEFORE delimiter, the inactive/active states reverse roles: the argument is in an active state when the scanning begins and becomes inactive at the character position that matches the delimiter. Regardless of the presence of the BEFORE delimiter, an argument becomes inactive when the scanner approaches the rightmost position of the item and the remaining characters are fewer in number than the characters in the argument. In such a case, the argument cannot possibly find a match in the item, so it becomes inactive.

Because the BEFORE/AFTER delimiters are found on a separate scan of the item, the compiler generates code that recognizes and sets up the delimiter boundaries before it scans for an argument match; therefore, the same characters can be used as arguments and delimiters in the same phrase.

5.3.4.3 Finding an Argument Match

The compiler generates code that selects arguments from the argument list in the order in which they appear in the list. If the first one it selects is an active argument, and the conditions stated in the INSPECT statement allow a comparison, the compiler generates code that compares it to the character at the scanner's position. If the active argument does not find a match, the compiler generates code that takes the next active argument from the list and compares that to the same character. If none of the active arguments finds a match, the scanner moves one position to the right and begins the inspection operation again with the first active argument in the list. The inspection operation terminates at the rightmost position of the item.

When an active argument finds a match, the compiler ignores any remaining arguments in the list and conducts the TALLYING or REPLACING operation on the character. The scanner moves to a new position and the next inspection operation begins with the first argument in the list. The INSPECT statement can contain additional conditions, which are described later in this section; without them, however, the argument match is allowed to take place, and inspection continues following the match.

The compiler updates the scanner by adding the size of the matching argument to it. This moves the scanner to the next character beyond the string of characters that matched the argument. Thus, once an active argument matches a string of characters, the statement does not inspect those character positions again unless program control executes the entire statement again.

5.3.5 The TALLYING Phrase

An INSPECT statement that contains a TALLYING phrase counts the occurrences of various character strings under certain stated conditions. It keeps the count in a user-designated item called a tally counter.

5.3.5.1 The Tally Counter

The identifier following the word TALLYING designates the tally counter. The identifier can be subscripted or indexed. The data item must be a numeric integer without any editing or P characters; it can be COMP or DISPLAY usage, and it can be signed (separate or overpunched).

Each time the tally argument matches the delimited string being inspected, the compiler adds 1 to the tally counter.

You can initialize the tally counter to any numeric value. The INSPECT statement does not initialize it.

5.3.5.2 The Tally Argument

The tally argument specifies a character-string (or strings) and a condition under which that string should be compared to the delimited string being inspected.

The CHARACTERS form of the tally argument specifies that every character in the delimited string being inspected should be considered to match an imaginary character that serves as the tally argument. This increments the tally counter by a value that equals the size of the delimited string. For example, the following statement causes TLY to be incremented by the number of characters that precede the first comma, regardless of what those characters are:


INSPECT FIELD1 TALLYING TLY FOR 
        CHARACTERS BEFORE ",". 

The ALL and LEADING forms of the tally argument specify a particular character-string (or strings), which can be represented by either a literal or an identifier. The tally argument character-string can be any length; however, each character of the argument must match a character in the delimited string before the compiler considers the argument matched.

The words ALL and LEADING supply conditions that further delimit the inspection operation:

Table 5-12 LEADING Delimiter of the Inspection Operation
Argument and Delimiter FIELD1 Value Contents of TLY After Scan
  F***0**F 2
  F**0F** 0
LEADING "*" AFTER "0". F**F**0 0
  0***F** 3
     
  F**0**F*** 1
  F**F0***FF 1
LEADING "**" AFTER "0". F**F0****F** 2
  F**F**0* 0

5.3.5.3 The Tally Argument List

One INSPECT...TALLYING statement can contain more than one tally argument, and each argument can have a separate BEFORE/AFTER phrase and tally counter associated with it. These tally arguments with their associated tally counters and BEFORE/AFTER phrases form an argument list. The manner in which this list is processed affects the action of any given tally argument.

The following examples show INSPECT statements with argument lists. The text with each example explains how that list is processed.


INSPECT FIELD1 TALLYING T FOR 
        ALL "," 
        ALL "." 
        ALL ";". 

These three tally arguments have the same tally counter, T, and are active over the entire item being inspected. Thus, the preceding statement adds the total number of commas, periods, and semicolons in FIELD1 to the initial value of T. Because the TALLYING phrase supports multiple arguments and only one counter is used, the previous statement could have been written as follows:


INSPECT FIELD1 TALLYING T FOR ALL "," "." ";". 


INSPECT FIELD1 TALLYING 
        T1 FOR ALL "," 
        T2 FOR ALL "." 
        T3 FOR ALL ";". 

Each tally argument in this statement has its own tally counter and is active over the entire item being inspected. Thus, the preceding statement adds the total number of commas in FIELD1 to the initial value of T1, the total number of periods to the initial value of T2, and the number of semicolons to T3.


INSPECT FIELD1 TALLYING 
        T1 FOR ALL "," AFTER "A" 
        T2 FOR ALL "." BEFORE "B" 
        T3 FOR ALL ";". 

Each tally argument in the preceding statement has its own tally counter; the first two arguments have delimiter phrases, and the last one is active over the entire item being inspected. Thus, the first argument is initially inactive and becomes active only after the scanner encounters an A; the second argument begins the scan in the active state but becomes inactive after a B has been encountered; and the third argument is active during the entire scan of FIELD1.

Table 5-13 shows various values of FIELD1 and the contents of the three tally counters after the scan of the previous statements. Assume that the counters are initialized to 0 before the INSPECT statement.

Table 5-13 Results of the Scan with Separate Tallies
  Contents of Tally Counters After Scan
FIELD1
Value
T1 T2 T3
A.C;D.E,F 1 2 1
A.B.C.D 0 1 0
A,B,C,D 3 0 0
A;B;C;D 0 0 3
*,B,C,D 0 0 0

The BEFORE/AFTER phrase applies only to the argument that precedes it and delimits the item for that argument only. Each BEFORE/AFTER phrase causes a separate scan of the item to determine the limits of the item for its corresponding argument.

5.3.5.4 Interference in Tally Argument Lists

When several tally arguments contain one or more identical characters active at the same time, they may interfere with each other, so that when one of the arguments finds a match, the scanner steps past any other matching characters, preventing those characters from being considered for a match.

The following two identical tally arguments do not interfere with each other because they are not active at the same time. The first A in FIELD1 causes the first argument to become inactive and the second argument to become active:


MOVE 0 TO T1 T2. 
INSPECT FIELD1 TALLYING 
        T1 FOR ALL "," BEFORE "A" 
        T2 FOR ALL "," AFTER "A". 

However, the next identical tally arguments interfere with each other since both are active at the same time:


INSPECT FIELD1 TALLYING 
        T1 FOR ALL "," 
        T2 FOR ALL "," AFTER "A". 

For any given position of the scanner, the arguments are applied to FIELD1 in the order in which they appear in the statement. When one of them finds a match, the scanner moves to the next position and ignores the remaining arguments in the argument list. Each comma in FIELD1 causes T1 to be incremented by 1 and the second argument to be ignored. Thus, T1 always contains an accurate count of all the commas in FIELD1, and T2 is always unchanged.

The following INSPECT statement arguments only partially interfere with each other:


INSPECT FIELD1 TALLYING 
        T2 FOR ALL "," AFTER "A" 
        T1 FOR ALL ",". 

The first argument does not become active until the scanner encounters an A. The second argument tallies all commas that precede the A. After the A, the first argument counts all commas and causes the second argument to be ignored. Thus, T1 contains the number of commas that precede the first A, and T2 contains the number of commas that follow the first A. This statement works well as written, but it could be difficult to debug.

The following three examples show that one INSPECT statement cannot count any character more than once. Thus, when you use the same character in more than one argument of an argument list, consider the possibility of interference and choose the order of the arguments carefully. The solution may require two or more INSPECT statements. Consider the following problem:


INSPECT FIELD1 TALLYING 
        T1 FOR ALL "AB" 
        T2 FOR ALL "BC". 

If FIELD1 contains ABCABC after the scan, T1 is incremented by 2, and T2 is unaltered. The successful matching of the argument includes each B in the item. Each match resets the scanner to the character position to the right of the B, so that the second argument is never successfully matched. The results remain the same even if the order of the arguments is reversed. Only separate INSPECT statements can develop the desired counts.

Sometimes you can use the interference characteristics of the INSPECT statement to your advantage. Consider the following sample argument list:


MOVE 0 TO T4 T3 T2 T1. 
INSPECT FIELD1 TALLYING 
        T4 FOR ALL "****" 
        T3 FOR ALL "***" 
        T2 FOR ALL "**" 
        T1 FOR ALL "*". 

The argument list counts all of the asterisks in FIELD1 in four different tally counters. T4 counts the number of times that four asterisks occur together; T3 counts the number of times three asterisks appear together; T2 counts double asterisks; and T1 counts singles.

If FIELD1 contains a string of more than four consecutive asterisks, the argument list breaks the string into groups of four and counts them in T4. It then counts the less-than-four remainder in T3, T2, or T1.

Reversing the order of the arguments in this list causes T1 to count all of the asterisks, and T2, T3, and T4 to remain unchanged.

When the LEADING condition is used with an argument in the argument list, that argument becomes inactive as soon as it fails to be matched in the item being inspected. Therefore, when two arguments in an argument list contain one or more identical characters and one of the arguments has a LEADING condition, the argument with the LEADING condition should appear first. Consider the following sample statement:


MOVE 0 TO T1 T2. 
INSPECT FIELD1 TALLYING 
        T1 FOR LEADING "*" 
        T2 FOR ALL "*". 

T1 counts only leading asterisks in FIELD1; the occurrence of any other character causes the first tally argument to become inactive. T2 keeps a count of any remaining asterisks in FIELD1.

Reversing the order of the arguments in the following statement results in an argument list that can never increment T1:


INSPECT FIELD1 TALLYING 
        T2 FOR ALL "*" 
        T1 FOR LEADING "*". 

If the first character in FIELD1 is not an asterisk, neither argument can match it, and the second argument becomes inactive. If the first character in FIELD1 is an asterisk, the first argument matches it and causes the second argument to be ignored. The first character in FIELD1 that is not an asterisk fails to match the first argument, and the second argument becomes inactive because it has not found a match in any of the preceding characters.

An argument with both a LEADING condition and a BEFORE phrase can sometimes successfully delimit the item being inspected, as in the following example:


MOVE 0 TO T1 T2. 
INSPECT FIELD1 TALLYING 
        T1 FOR LEADING SPACES 
        T2 FOR ALL "   " BEFORE "." 
        T2 FOR ALL "  " BEFORE "." 
        T2 FOR ALL " " BEFORE ".". 
IF T2 > 0 ADD 1 TO T2. 

These statements count the number of words in the English statement in FIELD1, assuming that no more than three spaces separate the words in the sentence, that the sentence ends with a period, and that the period immediately follows the last word. When FIELD1 has been scanned, T2 contains the number of spaces between the words. Because a count of the spaces renders a number that is one less than the number of words, the conditional statement adds 1 to the count.

The first argument removes any leading spaces, counting them in a different tally counter. This shortens FIELD1 by preventing the application of the second to the fourth arguments until the scanner finds a nonspace character. The BEFORE phrase on each of the other arguments causes them to become inactive when the scanner reaches the period at the end of the sentence. Thus, the BEFORE phrases shorten FIELD1 by making the second to the fourth arguments inactive before the scanner reaches the rightmost position of FIELD1. If the sentence in FIELD1 is indented with tab characters instead of spaces, a second LEADING argument can count the tab characters. For example:


INSPECT FIELD1 TALLYING 
        T1 FOR LEADING SPACES 
        T1 FOR LEADING TAB 
        T2 FOR ALL "    " 
        . 
        . 
        . 

When an argument list contains a CHARACTERS argument, it should be the last argument in the list. Because the CHARACTERS argument always matches the item, it prevents the application of any arguments that follow in the list. However, as the last argument in an argument list, it can count the remaining characters in the item being inspected. Consider the following example.


MOVE 0 TO T1 T2 T3 T4 T5. 
INSPECT FIELD1 TALLYING 
        T1 FOR LEADING SPACES 
        T2 FOR ALL "." BEFORE "," 
        T3 FOR ALL "+" BEFORE "," 
        T4 FOR ALL "-" BEFORE "," 
        T5 FOR CHARACTERS BEFORE ",". 

If FIELD1 is known to contain a number in the form frequently used to input data, it can contain a plus or minus sign, and a decimal point; furthermore, the number can be preceded by spaces and terminated by a comma. When this statement is compiled and executed, it delivers the following results:

The sum of T1 to T5, plus 1, gives the character position occupied by the terminating comma.


Previous Next Contents Index