I'm trying to use the INSPECT clause to see if a name (PIC X) contains a certain substring.
When I use
INSPECT NAME TALLYING COUNTER FOR ALL "lee"
The program works as expected,
When I replace the "lee" with a variable the command doesn't find anything.
...
WORKING-STORAGE SECTION.
01 ZOEKTERM PIC X(40).
...
MOVE "lee" TO ZOEKTERM
INSPECT NAAM TALLYING COUNTER FOR ALL ZOEKTERM
Can anyone explain why this is happening and what I can do about it?
The fix is to explictly specify the length.
...
WORKING-STORAGE SECTION.
01 ZOEKTERM PIC X(40).
01 ZOEKTERM-LEN PIC S9(4) COMP.
...
MOVE "lee" TO ZOEKTERM
MOVE 3 TO ZOEKTERM-LEN
INSPECT NAAM TALLYING COUNTER FOR ALL ZOEKTERM(1:ZOEKTERM-LEN)
The literal 'lee' is three characters long, while the ZOEKTERM is 40 characters long.
That affects the substrings they can match.
Bo Persson is correct. If you read the "Comparison cycle" in the documentation, you will see
The first comparand is compared with an equal number of leftmost contiguous character positions in the inspected item. The comparand matches the inspected characters only if both are equal, character-for-character.
Related
Given this working version
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO-WORLD.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 UC-COUNTER PIC 99.
01 LC-COUNTER PIC 99.
PROCEDURE DIVISION.
INSPECT "My dog has fleas"
TALLYING UC-COUNTER FOR ALL 'A','B','C','D','E','F',
'G','H','I','J','K','L','M','N','O','P','Q','R','S','T',
'U','V','W','X','Y','Z'
LC-COUNTER FOR ALL 'a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t',
'u','v','w','x','y','z'.
DISPLAY UC-COUNTER " UPPER CASE CHARACTERS".
DISPLAY LC-COUNTER " LOWER CASE CHARACTERS".
GOBACK.
Is there a better way of expressing the alphabets? That is, can we have a SPECIAL-NAMES or something like that so that the instruction can be INSPECT TALLYING FOR ALL LATIN-UPPERCASE-LETTERS-ENGLISH or something similar.
LATER
Things like this don't appear to work (and given the GnuCOBOL docs, probably won't)
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO-WORLD.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SPECIAL-NAMES.
CLASS UPPER-CASE-ENGLISH-LETTERS IS
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z'.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 UC-COUNTER PIC 99.
PROCEDURE DIVISION.
INSPECT "My dog has fleas"
TALLYING UC-COUNTER FOR ALL UPPER-CASE-ENGLISH-LETTERS.
DISPLAY UC-COUNTER " UPPER CASE CHARACTERS".
STOP RUN.
Is there a better way of expressing the alphabets?
COBOL has the class conditions ALPHABETIC-UPPER and ALPHABETIC-LOWER. Each of these includes space as part of the class condition. Unfortunately, for what you are requesting, class conditions cannot be used in an INSPECT statement.
It is necessary to simulate the INSPECT statement by using a loop to inspect each character to determine if it meets the class conditions while excluding spaces.
Code:
data division.
working-storage section.
01 uc-counter pic 99.
01 lc-counter pic 99.
01 str pic x(50).
01 n comp pic 9(4).
procedure division.
initialize uc-counter lc-counter
string "My dog has fleas" low-value delimited size
into str
perform varying n from 1 by 1
until str(n:1) = low-value
evaluate true
when str(n:1) = space
continue *> ignore space
when str(n:1) is alphabetic-upper
add 1 to uc-counter *> count upper-case letter
when str(n:1) is alphabetic-lower
add 1 to lc-counter *> count lower-case letter
when other
continue
end-evaluate
end-perform
display uc-counter " upper case characters"
display lc-counter " lower case characters"
goback
.
Output:
01 upper case characters
12 lower case characters
Depending on what character set you are using, if the characters are contiguous, then you could suffice with a few comparisons.
I was practicing array processing and table handling and there's this output of my program that I don't understand.
01 TABLE-VALUES.
05 TABLE-ELEMENTS OCCURS 2 TIMES.
10 A-A PIC X(5).
10 A-B PIC S9(5)V99 COMP-3.
01 WS-STRING PIC X(10).
01 S PIC 99.
01 WS-COUNT PIC 99.
...
PROCEDURE DIVISION.
0000-MAIN.
DISPLAY 'HELLO WORLD'
MOVE '1234567890ABCDEFGHI' TO TABLE-VALUES
DISPLAY 'TABLE VALUES ' TABLE-VALUES
MOVE 0 TO WS-COUNT
INSPECT TABLE-VALUES TALLYING WS-COUNT FOR CHARACTERS
DISPLAY WS-COUNT
PERFORM 1000-PARA VARYING S FROM 1 BY 1 UNTIL S > 2
STOP RUN.
1000-PARA.
MOVE 'A-A(&&) = ' TO WS-STRING
INSPECT WS-STRING REPLACING FIRST '&&' BY S
DISPLAY WS-STRING A-A(S)
MOVE 'A-B(&&) = ' TO WS-STRING
INSPECT WS-STRING REPLACING FIRST '&&' BY S
DISPLAY WS-STRING A-B(S).
The output turned out to be:
HELLO WORLD
TABLE VALUES 1234567890ABCDEFGHI
18
A-A(01) = 12345
A-B(01) = 6 7 8
A-A(02) = 0ABCD
A-B(02) = 5 6 7
I don't understand how A-B(1) and A-B(2) turned out like that. Why are there spaces in between? Where did digit 9 go to?
Try removing the COMP-3 from the A-B definition, it should work better.
Cobol comp-3
Comp-3 is cobol's binary coded decimal format. Each 4 bytes (1/2 byte or nyble) represents a decimal digit with the sign held in the last digit. Moving a character string to a comp-3 value (like you do) will result in a invalid comp-3 value.
Normally the value 1234 would be stored as
`01234C`x
In your case (if using an EBCDIC machine) you are moving 6789 hex string 'f6f7f8f9'x
to the variable A-B(01). The F's are not valid decimal digits and 9 is not a valid comp-3 sign.
Move to Table Explanation
Explanation of
MOVE '1234567890ABCDEFGHI' TO TABLE-VALUES
in the above TABLE-VALUES is treated as a pic x(18). The move completely ignores the definitions of A-A and A-B.
Assuming a definition of
01 TABLE-VALUES.
05 TABLE-ELEMENTS OCCURS 2 TIMES.
10 A-A PIC X(5).
10 A-B PIC S9(5)V99.
The following would make more sense
MOVE 'A-A 100234567A-A 200234567' TO TABLE-VALUES
When doing a move to a group level, The string has to exactly match the
map of the fields in the Group.
For the above Cobol Layout, the fields are aligned like
Field Position Length
A-A(1) 1 5
A-B(1) 6 7
A-A(2) 13 5
A-B(2) 18 7
I don’t know which compiler and directives you are using, but I would have expected the original DISPLAY of the comp-3 usage to ABEND with a numeric exception.
As for the follow up question about the letters in the numeric field, you valued the field by moving a literal to a group item, TABLE-VALUES. Group items always are USAGE ALPHANUMERIC.
According to the COBOL code below when I try to sum WS-NUM1 with WS-NUM2, COBOL seems to supress the last number. For example: variable WS-NUM1 and WS-NUM2 are 10.15, I get 20.20 as result but expected 20.30. What's wrong?
WS-NUM1 PIC 9(2)V99.
WS-NUM2 PIC 9(2)V99.
WS-RESULTADO PIC 9(2)V99.
DISPLAY "Enter the first number:"
ACCEPT WS-NUM1.
DISPLAY "Enter the second number:"
ACCEPT WS-NUM2.
COMPUTE WS-RESULTADO = WS-NUM1 + WS-NUM2.
Thanks in advance.
PIC 9(2)v99 defines a variable with an implied decimal place not a real one. You're trying to enter data containing a decimal point and it's not working because you have to strip out the '.' to get the numeric part of your data to properly fit in the 4 bytes that your working storage area occupies.
PROGRAM-ID. ADD2.
data division.
working-storage section.
01 ws-num-input pic x(5).
01 WS-NUM1 PIC 9(2)V99 value 0.
01 redefines ws-num1.
05 ws-high-num pic 99.
05 ws-low-num pic 99.
01 WS-NUM2 PIC 9(2)V99 value 0.
01 redefines ws-num2.
05 ws-high-num2 pic 99.
05 ws-low-num2 pic 99.
01 WS-RESULTADO PIC 9(2)V99.
PROCEDURE DIVISION.
DISPLAY "Enter the first number:"
*
accept ws-num-input
unstring ws-num-input delimited by '.'
into ws-high-num, ws-low-num
DISPLAY "Enter the second number:"
accept ws-num-input
unstring ws-num-input delimited by '.'
into ws-high-num2, ws-low-num2
*
COMPUTE WS-RESULTADO = WS-NUM1 + WS-NUM2.
DISPLAY WS-RESULTADO
STOP RUN
.
This is just a simple demonstration. In a real world application you would have to insure much more robust edits to ensure that valid numeric data was entered.
If I declare it like this
01 WS-NUM1 PIC 9(2)V99.
01 WS-NUM2 PIC 9(2)V99.
01 WS-RESULTADO PIC 9(2)V99.
and define and sum them up like this
SET WS-NUM1 TO 10.15.
SET WS-NUM2 TO 10.15.
COMPUTE WS-RESULTADO = WS-NUM1 + WS-NUM2.
DISPLAY WS-RESULTADO.
I get the expected result of 20.30.
This looks like a job for a special type of PICture : Edited picture
Indeed you seem to know about the vanilla PICture clause (I'm writing PICture because as you may know it you can either write PIC or PICTURE).
A vanilla number PIC contains only 4 different symbols (and the parentheses and numbers in order to repeat some of the symbols)
9 : Represents a digit. You can repeat by using a number between parentheses like said before.
S : Means that the number is signed
V : Show the position of the implicit decimal point
P : I've been told that it exists but I honestly never found it in the codebase of my workplace. Its another kind of decimal point used for scaling factors but I don't know much about it.
But there are other symbols.
If you use theses other mysterious symbols the numeric PIC becomes an edited numeric PIC. As its name says, an edited PICture is made to be shown. It will allow you to format your numbers for better presentation or to receive number formatted for human reading.
Once edited, you cannot use it to make computations so you will have to transfer from edited to vanilla to perform computations on the latter. And you move from vanilla to edited in order to display your results.
So now I shall reveal some of these mysterious symbols :
B : Insert a blank at the place it is put
0 : Insert a zero at the place it is put
. : Insert the decimal point at the place it is put
: Insert a + if the number is positive and a - if the number is negative
Z : Acts like a 9 if the digits it represents has a value different than 0. Acts like a blank if the digits has the value of 0.
To my knowledge there are also : / , CR DB * $ -
You can look up for it on the internet. They really show the accountant essence of cobol.
For your problems we are really interested by the "." which will allow us to take into account the decimal point you have the write when you type down your input.
For a bonus I will also use Z which will make your result looks like 2.37 instead of 02.37 if the number is less than ten.
Note that you cannot use the repeating pattern with parenthesis ( 9(03) for instance) when describing an edited picture ! Each digits has to represented explicitly
IDENTIFICATION DIVISION.
PROGRAM-ID. EDITCOMP.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-NUM1-EDITED PIC 99.99.
01 WS-NUM2-EDITED PIC 99.99.
01 WS-NUM1-CALC PIC 9(2)V99.
01 WS-NUM2-CALC PIC 9(2)V99.
01 WS-RESULTADO-EDITED PIC Z9.99.
PROCEDURE DIVISION.
ACCEPT WS-NUM1-EDITED.
ACCEPT WS-NUM2-EDITED.
MOVE WS-NUM1-EDITED TO WS-NUM1-CALC.
MOVE WS-NUM2-EDITED TO WS-NUM2-CALC.
COMPUTE WS-RESULTADO-EDITED = WS-NUM1-CALC + WS-NUM2-CALC.
DISPLAY WS-RESULTADO-EDITED.
STOP RUN.
You should note that there also exist edited alphanumeric picture. You can insert Blank (B), zeroes (0) or / (/) in it.
I am trying to accept input from jcl for example 'John Snow' and run it from my cobol program Im using JUSTIFIED RIGHT VALUE SPACES to move the string to the right side however I need to delete the extra spaces using my cobol pgm.
example
my working storage is:
01 ALPHA-ITEM PIC X(50).
01 MOVE-ITEM REDEFINES ALPHA-ITEM PIC X(50).
01 NUM-ITEM PIC X(50) JUSTIFIED RIGHT VALUE SPACES.
and in my PROCEDURE DIVISION
ACCEPT ALPHA-ITEM.
MOVE MOVE-ITEM TO NUM-ITEM.
DISPLAY NUM-ITEM.
it displays 'John Snow' on the right of the screen however i don't know how to remove the extra spaces.
you need something like this:
01 ALPHA-ITEM PIC X(50).
01 WS-INDEX PIC 99.
ACCEPT ALPHA-ITEM
PERFORM VARYING WS-INDEX
FROM 50 BY -1
UNTIL ALPHA-ITEM(WS-INDEX:1) NOT EQUAL SPACE
OR WS-INDEX < 1
END-PERFORM
DISPLAY ALPHA-ITEM(1:WS-INDEX).
This code will accept the alpha item, then run a loop to find out how long the data actually is. Then it will display that field starting from position 1 until the counter that was set in the loop.
There is also.. Unpopular for some reason.
UNSTRING MOVE-ITEM DELIMITED BY SPACES INTO NUM-ITEM.
I would like to write a function in COBOL that converts characters from a PIC X(60) data type to uppercase. While I know one way of doing this, I would like to be able to manually go through the letters and add a constant to go from lower case to upper case, but I cannot seem to be able to perform any arithmetic on PIC X data types, unless I redefine them as something else, but then I seem to corrupt the original X character.
Can someone give me an example of how, given a PIC X variable, you can increment it by 1 letter (i.e. a -> b, d -> e... etc). In other words, I would like to be able to add 1 to this variable:
01 char-temp pic x.
Thanks,
Ivan
It is usually a very bad idea to do case folding this way, it really only works for 7-bit ASCII. What you ask is possible, and even easy to do, but I'll mention some other ways to uppercase your data first.
Easiest way:
Move function upper-case(my-src-field) To my-tgt-field
Very easy way:
Inspect my-field
converting 'abc...z' to 'ABC...Z'
End-Inspect
Hard way, to add one to 01 char-temp pic x:
01 my-working-storage.
02 char-temp-area.
03 filler pic x.
03 char-temp pic x.
02 char-temp-9 redefines char-temp-area pic s9(4) comp
.
Then you can:
Move 'A' to char-temp
Add +1 to char-temp-9
And char-temp will contain a 'B'. As others have mentioned, Cobol is not nice about single byte binary math, so you have to make your character fit in the low byte of a binary number, in this case a 2 byte binary number.
You could be naughty and use redefines eg:
01 char-temp pic x.
01 char-temp9 pic 99 comp-x redefines char-temp.
move 65 to char-temp9
display char-temp
Or use reference modification:
01 char-temp pic x.
01 char-temp9 pic 99 comp-x.
move 65 to char-temp9
move char-temp9(1:length of char-temp9) to char-temp
display char-temp
and I am sure they are other approaches too...
A single character generally takes one byte of memory. Standard COBOL does not have a binary numeric data type of one byte (Note: PIC 9 USAGE DISPLAY is a character representation of a digit not the binary representation of the digit). So, doing binary arithemetic on single characters in COBOL isn't going to work for you.
Even if you could perform arithementic on characters, you may be making a bad assumption about the binary representation of characters - the letter 'b' is not necessarily equal to the binary representation of 'a' plus 1 (it might work for ASCII but not for EBCDIC).
Finally, if you want to replace one character by another you should investigate the COBOL INSPECT statement. Unlike bit twiddling, INSPECT is completely portable.
Can someone give me an example of how, given a PIC X variable, you can
increment it by 1 letter (i.e. a -> b, d -> e... etc). In other words,
I would like to be able to add 1 to this variable:
01 char-temp pic x.
For COBOL 85, intrinsic functions CHAR and ORD may be used.
program-id. add1.
data division.
working-storage section.
1 char-temp pic x.
procedure division.
begin.
move "a" to char-temp
display char-temp "->" with no advancing
perform add-1-to-char
display char-temp
stop run
.
add-1-to-char.
move function char (function ord (char-temp) + 1)
to char-temp
.
end program add1.
Result:
a->b