Joined: 03 May 2010 Posts: 154 Location: Kuala Lumpur
Hi,
I'm coding a CICS-COBOL program (Without any map and running in background), which is getting input from data power. As the data passing thru MQ, All I receive is string. I've to separate values by UNSTRING.
I'm also receiving more than 30 numeric data. I've to validate each and every value and convert into numeric.
IF WS-INPUT-ITEM-X > SPACES
COMPUTE WS-INPUT-ITEM = FUNCTION NUMVAL(WS-INPUT-ITEM-X)
ELSE
MOVE ZEROES TO WS-INPUT-ITEM.
(for more than 30 input fields).
Since NUMVAL function don't process SPACES and NON-NUMERIC item, I've added the condition "> SPACES" above.
I'm having little confusion for checking NON-NUMERIC values in those fields. I cannot use IS NUMERIC as it will omit values with spaces like '1234 '. I can use PERFORM to check each and every byte for non-numeric item but there are more than 30 variables and 10 bytes. so I would have to check 300 bytes. does anyone have better and simpler idea of how to achieve this?
Note: Since this is online program, it has to respond quickly as possible. can't take risk by doing code which take time. I've many other programs to code like this as well
Joined: 09 Mar 2011 Posts: 7309 Location: Inside the Matrix
You need to show some sample data.
When you show us code, it needs to compile. Yours does not.
Was there a "map" somewhere? without the data already right-alighned (or at least with a lenght) you are going to have more processing than necessary in your program. Nothing you can do about that. Design fault or laziness, probably both.
Joined: 03 May 2010 Posts: 154 Location: Kuala Lumpur
Bill Woodger wrote:
You need to show some sample data.
My requirement is simple. I just need to validate whether the input is numeric or not in the efficient way. it should allow space.
if input = '1234 ' then it need to convert.
if input = ' ' then move zeroes.
if input = 'abcdeas' then give error not abend (NUMVAL will abend).
When you show us code, it needs to compile. Yours does not.
You don't need my full code to understand. it is just a conversion of string to numeric. before convert I should validate the input.
Was there a "map" somewhere? without the data already right-alighned (or at least with a lenght) you are going to have more processing than necessary in your program. Nothing you can do about that. Design fault or laziness, probably both.
I've mentioned that there is no map for this program and it is BATCH CICS. data is passing from data power via MQ. I already find the way to do this (PERFORM and check each and every byte with IS NUMERIC and SPACE). I just need to know is there any other and efficient way to achieve this.
Joined: 09 Mar 2011 Posts: 7309 Location: Inside the Matrix
You've missed the point entirely. Your data didn't just appear "by magic". It came from somewhere. Wherever that "somewhere" is, the length of the data was known or it could have been right-justified (depending on the system that captured the data) through a "function" of the data capture.
Once you know the length of the field, you know how many leading zeros there should be as well. Put together your field as PIC X(10) and then test for NUMERIC.
I'm not sure for the amount of data that you have that you will be able to "notice" differences in the fix-up, unless you choose a very bad one.
Joined: 03 May 2010 Posts: 154 Location: Kuala Lumpur
Bill Woodger, I didn't mean to insult you. I just gave you a way of giving answers in short instead of confuse more.
Because, I've already mentioned that the input data coming from data power.
But I appreciate your efforts and that really helped me.
and for Pandora-Box: I think, you forget to notice "Thanks for your time. "
Joined: 09 Mar 2011 Posts: 7309 Location: Inside the Matrix
Again, I don't think you "got it".
I didn't say that so that next time you review a spec, you can say up front "there's a better way to do this".
I didn't say that because that can be implemented in many different ways, some slower than others, and some that won't work.
I didn't say that because other than your assertion, I have no reason to believe that the users would notice one implementation (your original) over something else.
Show us the code you have, and the code you come up with.
Establish, eimpirically, (mock it up) that what you have affects the response-time the user sees.
I respond in proportion to the amount and quality of information given.
EDIT: Don't imagine how other people feel about your messages. For me, it is of no concern how or what you write.
If you want something to be taken at "face value", don't put a smiley on it. Rather than wondering how someone "missed" your thanks, wonder instead what you have done to make them think it not genuine.
Joined: 14 Jan 2008 Posts: 2501 Location: Atlanta, Georgia, USA
It would be a great help to all if the inbound STRING were sub-divided into 'n' sub-strings, using a predefined separator character, similar to a CSV file. Then you can extract each sub-string and validate for numeric data.
Joined: 03 May 2010 Posts: 154 Location: Kuala Lumpur
My previous code:
Code:
01 WS-INPUT-ITEM-X PIC X(10) VALUE SPACES.
05 WS-INPUT-ITEM PIC 9(10) VALUE ZEROES.
PERFORM VARYING CTR1 FROM 1 BY 1 UNTIL CTR1 > 10
IF WS-INPUT-ITEM-X(CTR1:1) IS NOT NUMERIC AND
WS-INPUT-ITEM-X(CTR1:1) NOT = SPACE
MOVE 'ERROR' TO RESP-CODE
END-IF
END-PERFORM.
IF RESP-CODE = SPACES
COMPUTE WS-INPUT-ITEM =
FUNCTION NUMVAL (WS-INPUT-ITEM-X).
IF WS-INPUT-ITEM > SPACES
INSPECT WS-INPUT-ITEM-X REPLACING LEADING SPACES BY '0'
IF WS-INPUT-ITEM-X IS NUMERIC
COMPUTE WS-INPUT-ITEM = FUNCTION NUMVAL(WS-INPUT-ITEM-X)
ELSE
MOVE 'ERROR' TO RESP-CODE
END-IF
ELSE
MOVE ZEROES TO WS-INPUT-ITEM.
Robert: I'm using NUMVAL function to convert from string to numeric. I needed some quickest and easiest way for validate before convert. Thanks.
Bill O'Boyle: Separating values are already handled. thanks.
Bill Woodger: Is there anything else I could do to simplify the process ?
Joined: 14 Jan 2008 Posts: 2501 Location: Atlanta, Georgia, USA
OK, so each sub-string is 10-bytes, correct? And, how many sub-strings are there in one complete string? You had said 30, indicating that the total complete string is 300-bytes? Is this correct also?
You could calculate the max number of sub-strings and avoid hard-coding -
DIVIDE LENGTH OF "COMPLETE STRING" BY LENGTH OF WS-INPUT-ITEM GIVING WS-MAX-STRINGS
REMAINDER WS-REMAINDER.
If you have a remainder then there's a problem.
.
I didn't understand how this will validate whether the input string's each byte is numeric or not. I guess "WS-INPUT-ITEM" is input in your above code. "COMPLETE STRING" is also input?
Could you explain how your code works?
For your information, there are other input values too (some are date, time, plain text).
Joined: 03 May 2010 Posts: 154 Location: Kuala Lumpur
Bill O'Boyle : I don't know validating length will help to check whether the input string is numeric or not.
The "COMPLETE STRING" will contain many data including date, time, numeric & text, which are delimited by '~' symbol. I'm using UNSTRING to separate each values as I mentioned earlier.
All I asked is how to validate whether the input string is numeric or not in an easiest and simplest way.
Joined: 09 Mar 2011 Posts: 7309 Location: Inside the Matrix
At least you have progressed to using the Code Tags.
Thanks for that.
Or. Thanks for that :-) *
You continue to uphold something of an "attitude" towaards those trying to assist.
If you have 30 10-byte fields, then if their total length is not 300, then you know "something" is wrong, even if all is NUMERIC. We're more thorough than you are (yet). If there is something that is supposed to be true, we are perfectly happy to check it to prevent rubbish data from entering our systems.
With the original example, you still insist on including this:
Code:
01 WS-INPUT-ITEM-X PIC X(10) VALUE SPACES.
05 WS-INPUT-ITEM PIC 9(10) VALUE ZEROES.
That will not compile.
You have now mention that you have a fully delimited string. I assume all fields are "positional"?
This makes your code more "vulnerable", or your system more vulnerable to the accidental acquiring of bad data.
If one field is removed from the message, your numbers are no longer what you think they are. This can include the possibility of taking as input an 11-character field.
So, you have to do what you can to cover that. You have to "protect" your system;/yourself from the message-sender getting it wrong.
IF WS-INPUT-ITEM > SPACES
INSPECT WS-INPUT-ITEM-X REPLACING LEADING SPACES BY '0'
IF WS-INPUT-ITEM-X IS NUMERIC
COMPUTE WS-INPUT-ITEM = FUNCTION NUMVAL(WS-INPUT-ITEM-X)
ELSE
MOVE 'ERROR' TO RESP-CODE
END-IF
ELSE
MOVE ZEROES TO WS-INPUT-ITEM.
The VALUE ZEROES. on WS-INPUT-ITEM is spurious. Remove it.
Move the
Code:
MOVE ZEROES TO WS-INPUT-ITEM
so that it is before the block of code and unconditional. No-one reading the code then has to worry about how it gets set (does it have a VALUE, let me go back and look at that, is there a way out of the code without setting it, let me check that - all time wasted).
Whilst spurious before it is now totally superfluous. Remove
Code:
IF WS-INPUT-ITEM > SPACES
You have protected NUMVAL from leading space (which is unnecessary) but not from embedded space, which is necessary if you want to use NUMVAL and the data may contain embedded space. NUMVAL also has an intense dislike of non-numeric data which is not space, comma or full-stop/period. Forget NUMVAL, I would.
That leaves you with INSPECT. If you look at UNSTRING in the manual you will find that there is a COUNT which you can associate with an "unstrung" field. Means you can know the length of the data. Means you can 1) check the maximum length easily (remember Mr Bill) and 2) know how many leading-zeros there should be when the field is less than maximum length.
When you produce your "ERROR", how does the user know which field is in error?
'ERROR', a literal, is much better as a named field in the DATA DIVISION. If you use 'ERROR' as a literal in at least 30 places, you can guarantee that someone will want it changed to something else - and that change will have to be made in at least 30 places.
OK. So I guess you now know I'd do it differently.
I still can't say exactly how I'd do it, because I don't know all the information.
I can say "don't use NUMVAL". Because you are checking for non-numeric, it means that non-numeric is possible, which means that NUMVAL won't work.
I would 1) preserve the "input" field (the JUST RIGHT makes me think it is the target of the UNSTRING and then when you do the INSPECT its original content is lost - it is always good, for error situations, to be able to show the exact original).
I would use the COUNT (since UNSTRING sounds like a good choice so far) to tell how many leading zeros to insert - I'd do the insertion by defining the data.
If would ensure that the value from the COUNT is less than or equal to 10. If zero, I can do something if necessary for "no data".
Haviing inserted the correct number of leading zeros, simply test the temporay field for NUMERIC.
Joined: 03 May 2010 Posts: 154 Location: Kuala Lumpur
Bill Woodger wrote:
At least you have progressed to using the Code Tags.
Thanks for that.
Or. Thanks for that :-) *
You continue to uphold something of an "attitude" towaards those trying to assist.
If you have 30 10-byte fields, then if their total length is not 300, then you know "something" is wrong, even if all is NUMERIC. We're more thorough than you are (yet). If there is something that is supposed to be true, we are perfectly happy to check it to prevent rubbish data from entering our systems.
With the original example, you still insist on including this:
Code:
01 WS-INPUT-ITEM-X PIC X(10) VALUE SPACES.
05 WS-INPUT-ITEM PIC 9(10) VALUE ZEROES.
That will not compile.
I Just want to tell that, the code I pasted here is not same code. I've changed variable names and error message values and other details as per our company policies. Sure '01' and '05' is the typo and I can take care of this kind of errors.
Quote:
You have now mention that you have a fully delimited string. I assume all fields are "positional"?
This makes your code more "vulnerable", or your system more vulnerable to the accidental acquiring of bad data.
If one field is removed from the message, your numbers are no longer what you think they are. This can include the possibility of taking as input an 11-character field.
So, you have to do what you can to cover that. You have to "protect" your system;/yourself from the message-sender getting it wrong.
Separating input message is handled perfectly as per our system including unstring values, length of the value, etc.,. I don't know how many time I should tell this.
IF WS-INPUT-ITEM > SPACES
INSPECT WS-INPUT-ITEM-X REPLACING LEADING SPACES BY '0'
IF WS-INPUT-ITEM-X IS NUMERIC
COMPUTE WS-INPUT-ITEM = FUNCTION NUMVAL(WS-INPUT-ITEM-X)
ELSE
MOVE 'ERROR' TO RESP-CODE
END-IF
ELSE
MOVE ZEROES TO WS-INPUT-ITEM.
The VALUE ZEROES. on WS-INPUT-ITEM is spurious. Remove it.
Move the
Code:
MOVE ZEROES TO WS-INPUT-ITEM
so that it is before the block of code and unconditional. No-one reading the code then has to worry about how it gets set (does it have a VALUE, let me go back and look at that, is there a way out of the code without setting it, let me check that - all time wasted).
I guess, I need to remove all the 'VALUE' in the declaration just because, someone want to see my code and should not get confuse. And include another 30 'MOVE' statements instead. great help.
Quote:
Whilst spurious before it is now totally superfluous. Remove
Code:
IF WS-INPUT-ITEM > SPACES
You have protected NUMVAL from leading space (which is unnecessary) but not from embedded space, which is necessary if you want to use NUMVAL and the data may contain embedded space. NUMVAL also has an intense dislike of non-numeric data which is not space, comma or full-stop/period. Forget NUMVAL, I would.
I've used "IF WS-INPUT-ITEM > SPACES" to avoid empty values processing from INSPECT, NUMVAL. It is waste of run-time to process empty values in those. so I can just move zeroes to values.
For NUMVAL dislike of non-numeric data, I've checked IS NUMERIC before processing NUMVAL.
Quote:
That leaves you with INSPECT. If you look at UNSTRING in the manual you will find that there is a COUNT which you can associate with an "unstrung" field. Means you can know the length of the data. Means you can 1) check the maximum length easily (remember Mr Bill) and 2) know how many leading-zeros there should be when the field is less than maximum length.
I appreciate for this is information. I used INSPECT for the same. But can you tell me whether using UNSTRING and MOVE / INSPECT will be efficient for this process ?
Quote:
When you produce your "ERROR", how does the user know which field is in error?
'ERROR', a literal, is much better as a named field in the DATA DIVISION. If you use 'ERROR' as a literal in at least 30 places, you can guarantee that someone will want it changed to something else - and that change will have to be made in at least 30 places.
As I told earlier, The 'ERROR' tells you that, I've handled error. But it is actually a different message/code in there.
Quote:
OK. So I guess you now know I'd do it differently.
I still can't say exactly how I'd do it, because I don't know all the information.
I can say "don't use NUMVAL". Because you are checking for non-numeric, it means that non-numeric is possible, which means that NUMVAL won't work.
After checking with non-numeric, I finally have to convert the data to numeric. and of-course NUMVAL won't accept non-numeric and thats why I've asked here how to validate for numeric and of course, I've 'IS NUMERIC' condition before NUMVAL, which will eliminate the non-numeric items.
Quote:
I would 1) preserve the "input" field (the JUST RIGHT makes me think it is the target of the UNSTRING and then when you do the INSPECT its original content is lost - it is always good, for error situations, to be able to show the exact original).
I'm using temporary variables only.
Quote:
I would use the COUNT (since UNSTRING sounds like a good choice so far) to tell how many leading zeros to insert - I'd do the insertion by defining the data.
If would ensure that the value from the COUNT is less than or equal to 10. If zero, I can do something if necessary for "no data".
Haviing inserted the correct number of leading zeros, simply test the temporay field for NUMERIC.
More is difficult to say for now.
* requires reading an earlier post in the thread
This is the exact response I was expected. All of the above are non-related to my initial query. Thanks for your effort and time. I'll remove the INSPECT and use COUNT in UNSTRING to make efficient validation.
Note: don't read above statements like I'm showing 'attitude'. Just read calmly. You know these are just words, It is just the person, who decide how it should sound.
Joined: 09 Mar 2011 Posts: 7309 Location: Inside the Matrix
Suresh,
You read too fast, and with a "filter" that says "I know the information I want".
I have not tried to answer your question, because you have not, whatever you think, provided enough information to answer it.
Remember, or be aware of, that there are two "target audiences" for these topics. The TS/OP (that is you) and "others".
At least since I am unable to influence you, I can still hope that "others" get more out of what I've written.
Once you have the leading zeros and tested for NUMERIC, you no longer need NUMVAL at all. Total, utter, waste of time and resources. Just MOVE will be sufficient, and highly efficient.
Why test for "> spaces" when what you mean is "not equal to spaces"?
Yes, I take time to ensure that my programs are easy to understand. Once you know how to do it, it doesn't even take time. So, no extra time to code, save time in understanding vs your way.
COMPUTE WS-MAX-SUB = (LENGTH OF WS-STRING / LENGTH OF WS-INPUT-ITEM).
PERFORM UNTIL WS-SUB > WS-MAX-SUB
ADD 1 TO WS-POS
MOVE WS-STRING (WS-POS:LENGTH OF WS-INPUT-ITEM) TO WS-INPUT-ITEM (1:)
IF WS-INPUT-ITEM NOT NUMERIC
MOVE WS-SUB TO WS-ERROR-SUB
MOVE WS-MAX-SUB TO WS-SUB
END-IF
ADD 1 TO WS-SUB
ADD LENGTH OF WS-INPUT-ITEM TO WS-POS
END-PERFORM.
IF WS-ERROR-SUB > ZERO
DISPLAY 'SUB-STRING = ', WS-ERROR-SUB, ' IS NOT NUMERIC'
DISPLAY 'PLEASE REVIEW THIS DATA - VALIDATION PREMATURELY TERMINATED'
END-IF.
In this code, WS-MAX-SUB resolves as 30. The first '~' appears in WS-STRING at position 11 and subsequently at the "current' position plus 11. In between each '~', you'll find 10-bytes of data (a single sub-string).
This is based upon each sub-string being 10-bytes, which is the LENGTH OF WS-INPUT-ITEM.
WS-ERROR-SUB is set to the current value in WS-SUB when the current sub-string (found in WS-INPUT-ITEM) is NOT NUMERIC. When the PERFORM is completed, it's checked for a non-zero value. The PERFORM will be exited prematurely when the first NON NUMERIC sub-string is found.
Joined: 03 May 2010 Posts: 154 Location: Kuala Lumpur
Bill O'Boyle : As I mentioned earlier, I've some other input data in between numeric data like date, time & texts. So I can't follow your code. More are less it is checking each and every byte, which I've already used.
Bill Woodger:
1. I'm agreeing with your for replace NUMVAL with normal MOVE statement.
2. Anything <= SPACES will be non-process-able values(some times low-values). So I thought it is better to validate > SPACES.
3. If I follow UNSTRING with COUNT option,
a. I've to declare and process 30 more variables for COUNT
b. If there is SPACE in the input it will COUNT that as well. so I can't able to populate ZERO based on count.
for example: input = ' 1254', then count will be 6, so I'll populate 4 zeroes in front. So the values will be '0000 1254', which is incorrect.
Same goes for input = ' ' (all spaces), then count will be 10.
If I use INSPECT then it will replace all leading spaces into zeroes.
Am I missing anything ?
As for understand coding: We have number of programs coding and will have same structure as this, no need to go back and check what is the initial 'VALUE' for the TEMP variables as we follow 'SPACES' and 'ZEROES' for all TEMP variables we are using in whole program.
Joined: 14 Jan 2008 Posts: 2501 Location: Atlanta, Georgia, USA
One tip; If you're going to check each byte to be NUMERIC, check for NOT LESS THAN ZERO (X'F0') and NOT GREATER THAN '9' (X'F9'). This will generate two Assembler CLI (Compare Logical Immediate) instructions, which is far cheaper than a straight away NUMERIC check, which generates the far more expensive Assembler TRT (Translate and Test) instruction, utilizing a 256-byte translate-table built by the compiler and uses this byte-value as a displacement into the table (relative to zero), where the calculated table-address (when valid) will contain a X'00'.
Having attempted to understand your parsing/validation dilemma was a struggle, but apparently, there are hidden anomalies, which were not well documented, so my suggestions are over and good luck.
Joined: 09 Mar 2011 Posts: 7309 Location: Inside the Matrix
If checking byte-for-byte, do as Mr Bill says. The advanntage of IF ... NUMERIC for multiple bytes is that the instruction "stops" as soon as it finds a non-numeric. For one byte, this is not an advantage.
For the rest, if you're happy, we're happy.
The code will be tested.
I don't think an individual user will notice difference in response time.
I think if we really knew what you wanted, the provider of the message could have done more for you.
Let's let you get on with it, and stop pointing out stuff which you already know or are uninterested in.
You know all the details. We don't. Means we spend more time that necessary, only to get things patted away by you.
Next time, give us all the information up front, please.