Michael Coughlan
Page 47
overwritten, even though there are 13 characters in the moved text.
Example 15-8. Applying Reference Modification to an Alphanumeric String
Example 15-9 shows how to apply reference modification to the numeric data item nString and the edited
numeric data item enString:
• In nString, reference modification is used to display the dollars and cents parts of a
numeric value.
• In enString, reference modification is used to overwrite the check-security asterisks with
the @ symbol. Note that ALL "@" is a figurative constant that is used to fill the four character positions specified by the reference modifier.
382
Chapter 15 ■ String Manipulation
Example 15-9. Applying Reference Modification to Numeric Data Items
Intrinsic Functions
User-defined functions of one sort or another are a standard part of many programming languages. The ANS 85
version of COBOL does not support user-defined functions, but it has introduced a library of standard functions called intrinsic functions.
Intrinsic functions fall into three broad categories: date functions, numeric functions, and string functions.
Because this chapter is about string manipulation, I discuss the string functions in some detail. I also look at the date functions and some of the numeric functions that I have found particularly useful. For the remaining functions you should consult your implementer manual.
Using Intrinsic Functions
Like a function in another language, an intrinsic function is replaced by the function result in the position where the function occurs. Wherever you can use a literal, you can use an intrinsic function that returns a result of the same type.
An intrinsic function consists of three parts:
• The start of the function is signalled by the FUNCTION keyword.
• The FUNCTION keyword is followed by the name of the function.
• The name of the function is immediately followed by a bracketed list of
parameters or arguments.
383
Chapter 15 ■ String Manipulation
• The intrinsic function template is
FUNCTION FunctionName(Parameter)
where FunctionName is the name of the function and Parameter is one or
more parameters/arguments supplied to the function.
For instance, the following examples show how to use intrinsic functions in a number of different contexts. In some cases, the result of the function is assigned to a data item; in others (as in the first example), it is used directly in the place of a literal or data item. Sometimes the parameters/arguments are numeric, and other times they are alphabetic. Some functions use only one parameter, others take multiple parameters, and still others do not require a parameter:
DISPLAY FUNCTION UPPER-CASE("this will be in upper case").
MOVE FUNCTION ORD("A") TO OrdPos
MOVE FUNCTION RANDOM(SeedValue) TO RandomNumber
MOVE FUNCTION RANDOM TO NextRndNumber
COMPUTE Result = FUNCTION MOD(25, 10)
MOVE FUNCTION ORD-MAX(12 23 03 78 65) TO MaxOrdPos
When you use intrinsic functions, you must bear in mind a number of things:
• Intrinsic functions return a result of Alphanumeric, Numeric (includes integer), or Integer
(does not allow the decimal point).
• The result returned by an alphanumeric function has an implicit usage of DISPLAY. This is why
the result returned by FUNCTION UPPER-CASE may be used directly with the DISPLAY verb.
• Intrinsic functions that return a numeric value are always considered to be signed and can
only be used in an arithmetic expression or a MOVE statement.
• Intrinsic functions that return a non-integer numeric value can’t be used where an integer
value is required.
String Functions
Table 15-1 lists the intrinsic functions that allow manipulation of strings. The table uses the parameter name to indicate the type of the parameter required, as follows:
Alpha indicates Alphanumeric.
Num indicates any Numeric.
PosNum indicates a positive Numeric.
Int indicates any Integer.
PosInt indicates a positive Integer.
Any indicates that the parameter may be of any type.
384
Chapter 15 ■ String Manipulation
Table 15-1. String Functions, Grouped by Type of Operation
Function Name
Result Type
Comment
CHAR(PosInt)
Alphanumeric
Returns the character in the collating sequence at ordinal position
PosInt.
ORD(Alpha)
Integer
Returns the ordinal position of character Alpha.
ORD-MAX({Any}...)
Integer
Returns the ordinal position of whichever parameter in the list has
the highest value. All parameters must be of the same type. The
parameter list may be replaced by an array. If an array is used, the
reserved word ALL may be used as the array subscript to indicate
all the elements of the array.
ORD-MIN({Any}...)
Integer
Returns the ordinal position of whichever parameter in the list
has the lowest value. All parameters must be of the same type. The
parameter list may be replaced by an array.
LENGTH(Any)
Integer
Returns the number of characters in the data item Any. Not as
useful as it sounds. It returns the value given in the item’s picture
clause. For instance, Length(StrItem) returns 18 if the picture
clause is PIC X(18).
REVERSE(Alpha)
Alphanumeric
Returns a character string with the characters in Alpha reversed.
LOWER-CASE(Alpha)
Alphanumeric
Returns a character string with the characters in Alpha changed to
their lowercase equivalents.
UPPER-CASE(Alpha)
Alphanumeric
Returns a character string with the characters in Alpha changed to
their uppercase equivalents.
If a function takes a parameter list (indicated by {Any}... in the function definition), the parameter list may be replaced by an array. The reserved word ALL is used as the array subscript to indicate all the elements of the array.
For instance, the ORD-MAX function may take a parameter list, or you can use an array as the parameter, as shown in the following example:
MOVE FUNCTION ORD-MAX(12 23 03 78 65) TO OrdPos
or
MOVE FUNCTION ORD-MAX(IntElement(ALL)) TO OrdPos
String Intrinsic Function Examples
Listing 15-9 solves no specific problem. It merely consists of a number of intrinsic function examples.
Listing 15-9. String Manipulation with Intrinsic Functions
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing15-9.
AUTHOR. Michael Coughlan.
*> Intrinsic Function examples
385
Chapter 15 ■ String Manipulation
DATA DIVISION.
WORKING-STORAGE SECTION.
01 OrdPos PIC 99.
01 TableValues VALUE "123411457429130938637306851419883522700467".
02 Num PIC 99 OCCURS 21 TIMES.
01 idx PIC 9.
01 xString PIC X(45)
VALUE "This string is 33 characters long".
01 xWord PIC X(10).
01 CharCount PIC 99.
01 TextLength PIC 99.
PROCEDURE DIVISION.
Begin.
*> eg1. In the ASCII collating sequence W has a code of 87 but an ordinal
*> position of 88.
&n
bsp; DISPLAY "eg1. The character in position 88 is = " FUNCTION CHAR(88)
*> eg2. Using ordinal positions to spell out my name
DISPLAY SPACES
DISPLAY "eg2. My name is " FUNCTION CHAR(78) FUNCTION CHAR(106)
FUNCTION CHAR(108) FUNCTION CHAR(102)
*> eg3. Finding the ordinal position of a particular character
DISPLAY SPACES
MOVE FUNCTION ORD("A") TO OrdPos
DISPLAY "eg3. The ordinal position of A is = " OrdPos
*> eg4. Using CHAR and ORD in combination to display the sixth letter of the alphabet
DISPLAY SPACES
DISPLAY "eg4. The sixth letter of the alphabet is "
FUNCTION CHAR(FUNCTION ORD("A") + 5)
*> eg5. Finding the position of the highest value in a list of parameters
DISPLAY SPACES
MOVE FUNCTION ORD-MAX("t" "b" "x" "B" "4" "s" "b") TO OrdPos DISPLAY "eg5. Highest character in the list is at pos " OrdPos
*> eg6. Finding the position of the lowest value in a list of parameters
DISPLAY SPACES
MOVE FUNCTION ORD-MIN("t" "b" "x" "B" "4" "s" "b") TO OrdPos DISPLAY "eg6. Lowest character in the list is at pos " OrdPos
386
Chapter 15 ■ String Manipulation
*> eg7.Finding the position of the highest value
in a table
DISPLAY SPACES
MOVE FUNCTION ORD-MAX(Num(ALL)) TO OrdPos
DISPLAY "eg7. Highest value in the table is at pos "
OrdPos
*> eg8. Finding the highest value in a table
DISPLAY SPACES
DISPLAY "eg8. Highest value in the table = "
Num(FUNCTION ORD-MAX(Num(ALL)))
*> eg9. Finds the top three values in a table by finding the top
*> overwrites it with zeros to remove it from consideration
*> then finds the next top and so on
DISPLAY SPACES
DISPLAY "eg9."
PERFORM VARYING idx FROM 1 BY 1 UNTIL idx > 3
DISPLAY "TopPos " idx " = " Num(FUNCTION ORD-MAX(Num(ALL)))
MOVE ZEROS TO Num(FUNCTION ORD-MAX(Num(ALL)))
END-PERFORM
*> eg10. Finding the length of a string
DISPLAY SPACES
DISPLAY "eg10. The length of xString is " FUNCTION LENGTH(xString) " characters"
*> eg11. Finding the length of the text in a string
DISPLAY SPACES
INSPECT FUNCTION REVERSE(xString) TALLYING CharCount
FOR LEADING SPACES
COMPUTE TextLength = FUNCTION LENGTH(xString) - CharCount
DISPLAY "eg11. The length of text in xString is " TextLength " characters"
*> eg12. Discover if a word is a palindrome
DISPLAY SPACES
DISPLAY "eg12."
MOVE ZEROS TO CharCount
DISPLAY "Enter a word - " WITH NO ADVANCING
ACCEPT xWord
INSPECT FUNCTION REVERSE(xWord)
TALLYING CharCount FOR LEADING SPACES
IF FUNCTION UPPER-CASE(xWord(1:FUNCTION LENGTH(xWord) - CharCount)) EQUAL TO
FUNCTION UPPER-CASE(FUNCTION REVERSE(xWord(1:FUNCTION LENGTH(xWord)- CharCount)))
DISPLAY xWord " is a palindrome"
ELSE
DISPLAY xWord " is not a palindrome"
END-IF
STOP RUN.
387
Chapter 15 ■ String Manipulation
Program Explanation
These examples build on one another so that although the early ones are straightforward, the later ones are somewhat more complex and require explanation. One thing you will realize from these examples is that COBOL’s intrinsic functions are not as effective as functions in other languages. For one thing, the requirement to precede every intrinsic function with the word FUNCTION makes nesting functions cumbersome. For another, the function library is incomplete. You often have to use INSPECT, UNSTRING, and STRING to compensate for omissions. On the other hand, not being able to nest functions deeply may be a good thing. For instance, eg12 would require more typing but would be easier to understand and debug if coded as follows:
*>eg12. Discover if a word is a palindrome
DISPLAY SPACES
DISPLAY "eg12."
MOVE ZEROS TO CharCount
DISPLAY "Enter a word - " WITH NO ADVANCING
ACCEPT xWord
INSPECT FUNCTION REVERSE(xWord) TALLYING CharCount
FOR LEADING SPACES
MOVE FUNCTION UPPER-CASE(xWord) TO xWord
COMPUTE TextLength = FUNCTION LENGTH(xWord) - CharCount
IF xWord(1:TextLength) EQUAL TO FUNCTION REVERSE(xWord(1:TextLength))
DISPLAY xWord " is a palindrome"
ELSE
DISPLAY xWord " is not a palindrome"
END-IF
Let’s look at how these examples work:
• eg1 uses the CHAR function to return the eighty-eighth character ( W) of the ASCII collating
sequence. In most languages, you would be required to supply the ASCII value, whereas in
COBOL you supply the ordinal position. If you are used to dealing with ASCII values, the
ordinal position will seem to be off by one: for example, the ASCII value of W is 87.
• eg2 uses the CHAR function to display the name Mike.
• eg3 demonstrates that the ORD function is the opposite of CHAR. Whereas CHAR returns the
character at the ordinal position supplied, ORD returns the ordinal position of the character
supplied. As you no doubt know, A is ASCII value 65, but its ordinal position is returned as 66.
• eg4 is the first use of nested functions. CHAR and ORD are used in combination. ORD("A")
returns the position of the first letter in the alphabet, and the sixth is five letters on from that.
• eg5 and eg6 demonstrate using the ORD-MAX function to find the position of the highest value
in the supplied list.
• eg7 demonstrates how to use ORD-MAX to find the position of the highest value in a table.
• eg8 uses nesting and ORD-MAX to find the highest value in a table.
• Eg9 uses the techniques demonstrated in eg7 and eg8 to find the top three values in a table.
Each time through the loop, the highest value is found, displayed, and then overwritten with
zeros to remove it from consideration the next time around. This solution does have the
drawback of destroying some of the values in the table.
388
Chapter 15 ■ String Manipulation
• eg10 and eg11: one problem COBOL has is that alphanumeric data items are fixed in length, so
if the text does not fill the data item, the data item is space-filled to the right. For certain kinds
of processing, this is a problem. eg10 shows how to get the length of a data item, and eg11
shows how to use the length of the data item to get the length of the text in that data item.
• eg12 brings together much of the material covered in this chapter. The task is to discover
whether a word entered by the user is a palindrome (reads the same backward as forward). As
I noted earlier, the nesting of functions makes the program much more difficult to understand.
This is the algorithm: using the technique of eg11, find the actual length of the word.
Use reference modification to select only the word from the data item xWord, change it
to uppercase, and compare it to a reversed, uppercased, version of the word. If they are
equal, then the word is a palindrome.
DATE Functions
Date functions are a homogeneous group of functions that are often very useful. Table 15-2 lists the functions.
The table uses the same parameter type indicators as Table 15-1 (Alpha, Num, PosNum, Int, PosInt, Any).
Table 15-2. Date Functions
Function Name
/>
Result Type
Comment
CURRENT-DATE
Alphanumeric
Returns a 21-character string representing the current
date and time, and the difference between the local time
and Greenwich Mean Time. The format of the string is
YYYYMMDDHHMMsshhxhhmm, where YYYY is the year,
MM is the month, DD is the day of the month, HH is the hour
(24-hour time), MM is the minutes, ss is the seconds, and
hh is the hundredths of a second. In addition, xhhmm is the
number of hours and minutes the local time is ahead of or
behind GMT ( x = + or - or 0). If x = 0, the hardware cannot
provide this information.
DATE-OF-INTEGER(PosInt)
Integerof the
Converts the integer date PosInt (representing the number
form YYYYMMDDD
of days that have passed since Dec 31, 1600 in the Gregorian
calendar) to a standard date. Returns the standard date in the
form YYYYMMDD. This function can be useful when you are
calculating the number of days between two dates.
DAY-OF-INTEGER(PosInt)
Integer of the
Converts the integer date PosInt(representing the number
form YYYYDDD
of days that have passed since Dec 31, 1600 in the Gregorian
calendar) to a standard date of the form YYYYDDD
(sometimes called a Julian date).
INTEGER-OF-DATE(PosInt)
Integer
Converts the standard date PosInt (in the form YYYYMMDD)
into the equivalent integer date. If PosInt is not a valid date,
then zeros are returned.
INTEGER-OF-DAY(PosInt)
Integer
Converts the standard date PosInt (in the form YYYYDDD—a
Julian date) into the equivalent integer date.
WHEN-COMPILED
Integer
Returns the date and time the program was compiled. Uses
the same format as CURRENT-DATE.