Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Numeric field at end of UNSTRING

Status
Not open for further replies.

SiouxCityElvis

Programmer
Jun 6, 2003
228
US
I am Reading in a sequential file:

TestDataFile.csv
SELECT TESTDATA-FILE ASSIGN TO "TestDataFile.csv"
ORGANIZATION IS LINE SEQUENTIAL
ACCESS IS SEQUENTIAL.

FD TESTDATA-FILE.
01 TESTDATA-FILE-RECORD PIC X(16).

I unstring it into Working Storage fields.
WORKING STORAGE.

01 WS-MSG-RECORD.
02 WS-MSG-FIELDS.
03 WS-MSG-FIELD-1 PIC X(4).
03 WS-MSG-FIELD-2 PIC X(4).
03 WS-MSG-FIELD-3 PIC X(4).
03 WS-MSG-FIELD-4 PIC 9(4).

My UNSTRING Statement is as follows:

UNSTRING-TEST-DATA.
READ TESTDATA-FILE NEXT RECORD
AT END DISPLAY "DONE READING"
NOT AT END
UNSTRING TESTDATA-FILE-RECORD DELIMITED BY ","
INTO
WS-MSG-FIELD-1
WS-MSG-FIELD-2
WS-MSG-FIELD-3
WS-MSG-FIELD-4
END-UNSTRING
END-READ.

Okay. So, when I look at my sequential file it looks like:

abcd,dcba,cbda,4444

But, later in my code after I UNSTRING into my WS fields and do a DISPLAY of my WS-MSG-FIELD-4 it always has 0000 as its value. I find that if I make my TestDataFile.csv record with a trailing comma afer the 4444 i.e.

abcd,dcba,cbda,4444,

My 4444 will show up instead of 0000.
Also, if I don't put a comma after 4444 in my comma-delimited record in TestDataFile.csv, but change my WS-MSG-FIELD-4 to PIC X(4), it shows up on the DISPLAY statement, but is useless when comparing it to a numeric defined value off of another field in a different datafile.

Any suggestions as to how to fix this?
The reason I ask, is because when I load my .csv file into the environment, I don't think I will be expecting to have a "," after the last field(numeric field) on each record. So, I want to be able to handle this properly through my code and by not manually putting a comma after the last field on each record in my sequential .csv file.

Thanks in advance.

-David
 
Sounds to me like you are not supplying a record delimiter at the end of each record. Delimited files use delimiters between fields and to signal the end of a record. I'm not an expert here, so you may want to wait for additional responses.

Hope that helps!
 
Hi, David.

First, you say that the sequential record is described
Code:
FD TESTDATA-FILE.
01 TESTDATA-FILE-RECORD    PIC X(16).
                                 ^^
which probably will not successfully contain the 19 characters
Code:
abcd,dcba,cbda,4444

So I will assume that your record description is actually larger than PIC X(16). From this I will extrapolate that your last field is actually "4444 ", that is, your numeric digits followed by some number of spaces. The rule for moving an alphanumeric data item to a numeric data item is to treat the alphanumeric data item as if it were described as an unsigned numeric integer. Presumably the last few characters are spaces which, for the purposes of the move, are treated as if they were zeros, and the result is that you get a zero value stored in your numeric receiving item.

If your first three fields do not contain embedded spaces then you could use:
Code:
UNSTRING TESTDATA-FILE-RECORD DELIMITED BY "," OR ALL " "
    INTO
      WS-MSG-FIELD-1
      WS-MSG-FIELD-2
      WS-MSG-FIELD-3
      WS-MSG-FIELD-4
END-UNSTRING

If your data might contain embedded spaces, the solution is a bit more complex. Think in terms of two UNSTRING statements which use POINTER to track position in the sending field.


Tom Morrison
 
Hi

What happens if u change the pic 9(04) to x(04) and then do explicit move to a 9(04). I am really doubtful whether u can specify a numeric variable as a receiving operand in a unstring operation.

Why not give a try !!!

Devesh
 
Davesh,

The COBOL standard allows the destination operand(s) to be numeric. The only restriction is that USAGE must be DISPLAY. However, once the UNSTRING operation determines which source operand characters are to be moved to the destination operand, those source operand characters are treated as if they were an elementary alphanumeric item of the same size. Therefore, when you have a numeric destination item, the move obeys the rules of alphanumeric-to-numeric which are also described in the COBOL standard, viz. the contents of the source operand is to be treated as if it were an unsigned integer.

I know this is a bit arcane, and it definitely would lead the prudent programmer to avoid numeric destinations. [smile]

Tom Morrison
 
As a follow-on to that last post, I think it will be important to know exactly WHAT the format of that last field might be - in the input record.

Can it be
"4444 "
Can it be
"4444" or "444" or "44"
Might it ever be
"4,444.44"

Will it always be followed by spaces? By end-of-record (line sequential-type) delimiter?

Once you have this information, it will be possible to determine *IF* there would be a variation of UNSTRING that would correctly move it to a numeric receiving field. Clearly another possibilitiy (depending upon the input format) would be to UNSTRING it to an alphanumeric field and use the NumVAL intrinsic function to "convert" the field to a numeric one.
 
Hi, Bill.

Well David won't be able to use the Numval intrinsic function since RM/COBOL does not have that available. What is available is the possibility of redefining the alphanumeric field with numeric edited:
Code:
   03  RX-FIELD   PIC X(20).
   03  RX-NUM-FIELD REDEFINES RX-FIELD PIC Z(20).

Then, MOVE after the UNSTRING, such as:
Code:
   UNSTRING  .....
       INTO RX-FIELD
       .....
   END-UNSTRING.
   MOVE RX-NUM-FIELD TO
numeric-item

This used the deedit capability of the MOVE statement.

Tom Morrison
 
WMK,

WS-MSG-FIELD-4 is going to eventually end up being for a check amount of ####.## format.

But, right now, I'm taking smaller steps and just defining it as PIC 9(4) and have noticed that it does not work.

I tried Deveshjogal's method of defining it as PIC X(4) and it will show up in a DISPLAY statement but be useless as a comparison to another field with a PIC 9(4).

My statements in my original post describe this further:
abcd,dcba,cbda,4444,

My 4444 will show up instead of 0000.
"Also, if I don't put a comma after 4444 in my comma-delimited record in TestDataFile.csv, but change my WS-MSG-FIELD-4 to PIC X(4), it shows up on the DISPLAY statement, but is useless when comparing it to a numeric defined value off of another field in a different datafile."

Tom, is there a better alternative approach to this than using the UNSTRING. I'm not too clear on your last post.

Thanks.
-David
 
David,

I will assume that your input free-format fields do not contain embedded spaces. Now I will make some changes to your code:
Code:
01 WS-MSG-RECORD.
   02 WS-MSG-FIELDS.
      03 WS-MSG-FIELD-1     PIC X(4).
      03 WS-MSG-FIELD-2     PIC X(4).
      03 WS-MSG-FIELD-3     PIC X(4).
Code:
      03 WS-MSG-FIELD-4     PIC X(18).
      03 VAL-OF-WS-MSG-FIELD-4 PIC Z(18)
         REDEFINES WS-MSG-FIELD-4.
      03 NUMERIC-FIELD-4    PIC S9(15)V99.
Code:
UNSTRING TESTDATA-FILE-RECORD DELIMITED BY ","
Code:
 OR ALL " "
Code:
  INTO
    WS-MSG-FIELD-1
    WS-MSG-FIELD-2
    WS-MSG-FIELD-3
    WS-MSG-FIELD-4
END-UNSTRING
Code:
MOVE VAL-OF-WS-MSG-FIELD-4 TO NUMERIC-FIELD-4

Now you may use NUMERIC-FIELD-4 for your comparison to another numeric data item.

Go ahead and try this with something like:
Code:
abcd,dcba,cbda,4433.22


Tom Morrison
 
Tom:
I think your process may have a flaw.

01 WS-MSG-RECORD.
02 WS-MSG-FIELDS.
03 WS-MSG-FIELD-1 PIC X(4).
03 WS-MSG-FIELD-2 PIC X(4).
03 WS-MSG-FIELD-3 PIC X(4).
03 WS-MSG-FIELD-4 PIC X(18).
03 VAL-OF-WS-MSG-FIELD-4 PIC Z(18)
REDEFINES WS-MSG-FIELD-4.
03 NUMERIC-FIELD-4 PIC S9(15)V99.

UNSTRING TESTDATA-FILE-RECORD DELIMITED BY "," OR ALL " "
INTO
WS-MSG-FIELD-1
WS-MSG-FIELD-2
WS-MSG-FIELD-3
WS-MSG-FIELD-4
END-UNSTRING
MOVE VAL-OF-WS-MSG-FIELD-4 TO NUMERIC-FIELD-4

You're unstringing into a PIC X(18) field. It will left justify the value and pad trailing spaces. You have redefined that with a Z(18). The Z edit picture is for leading spaces. When you try to de-edit by moving to the numeric field, there are no leading spaces.

I tried it using 4444 as the value and the final numeric field has 4000000000000000. Also, you're trying to move a
Z(18) with no decimals to a S9(15)V99 (2 decimals). Your redefinition is going to need decimal positions defined if it is to de-edit correctly.
 
Lunker,

As mentioned in thread209-533708, RM/COBOL has more relaxed rules than other implementations. In particular, it uses only the fact that the data item is numeric edited, not the actual editing picture. This behavior anticipated the intrinsic function numval behavior. RM/COBOL customers had been using this particular behavior for years before the 1985 standard in the ACCEPT ... CONVERT verb used for screen input directly into a numeric item.

So, I stand by my explanation. It is for RM/COBOL only. Others should use NUMVAL.

Tom Morrison
 
Tom

This shud give a problem. in this case z(18) will be moved into 9(15). So u will loose 3 left side digits. The main problem is the number is left alligned like a text.

He has to add JUST RIGHT to the item 4.

The definition will be somewhat like this

01 WS-MSG-RECORD.
03 WS-MSG-FIELD-1 PIC X(4).
03 WS-MSG-FIELD-2 PIC X(4).
03 WS-MSG-FIELD-3 PIC X(4).
03 WS-MSG-FIELD-4 PIC X(18) JUST RIGHT.
03 VAL-OF-WS-MSG-FIELD-4
REDEFINES WS-MSG-FIELD-4 PIC Z(15).99.


01 NUMERIC-FIELD-4 PIC S9(15)V99.

UNSTRING TESTDATA-FILE-RECORD DELIMITED BY "," OR ALL " "
INTO
WS-MSG-FIELD-1
WS-MSG-FIELD-2
WS-MSG-FIELD-3
WS-MSG-FIELD-4
END-UNSTRING
MOVE VAL-OF-WS-MSG-FIELD-4 TO NUMERIC-FIELD-4

DISPLAY WS-MSG-FIELD-1
DISPLAY WS-MSG-FIELD-2
DISPLAY WS-MSG-FIELD-3
DISPLAY WS-MSG-FIELD-4
DISPLAY NUMERIC-FIELD-4.

Only problem will be he shud always have the last number field with 2 decimal places.



Devesh
 
Tom

Again by the time I test and write, U have updated %-)
But i think my solution will work in RM/COBOL too.
any comments welcome !!!

Devesh
 
Devesh,

Yes, yours will work, too, because it still gets the value in the field, and still redefines it as numeric edited.

Because you are using JUST, your code will exhibit a different failure mode if the final field contains too many characters. Yours will get the rightmost characters, while mine will get the leftmost.

Tom Morrison
 
Elvis

You had the right idea when you broke your problem into "smaller steps", as you put it.

If you had broken the problem into an even smaller step, I think you may have solved it.

I think you need to go back to basics of how the UNSTRING verb actually works.

When you unstring a field into an alphanumeric, what alignment happens?

INITIALIZE WX-RECV-FLD. <=== PIC X(12)
UNSTRING '4444 '
INTO WX-RECV-FLD.

When you unstring a field into a numeric, what
alignment happens?
INITIALIZE W9-RECV-FLD. <=== PIC 9(6)V9(6).
UNSTRING '4444 '
INTO W9-RECV-FLD.

Your experiments should show justification to the left for alphanumeric receiving fields, and justification on the decimal point for numeric receiving fields.

Armed with these basics, I think you would have solved the problem.

The other thing you may not have realized is that you can nominate more than one delimiter (as others have shown in their examples).

INITIALIZE W9-RECV-FLD. (& others)
UNSTRING 'A,B,C,4444 '
DELIMITED ALL SPACES OR ','
INTO
WX-RECV-FLD1
WX-RECV-FLD2
WX-RECV-FLD3
W9-RECV-FLD
END-UNSTRING.

The ALL SPACES delimiter will solve the problem of the trailing spaces going into the recv fld justified on the decimal point, and truncating the leading 4444 because the recv fld was to small.

Hope this helps.

Try some experiments with POINTER, COUNT and TALLYING - it's very interesting.
 
Terminate,

You said, Your experiments should show ... justification on the decimal point for numeric receiving fields.

As explained above, this is because the characters selected by the UNSTRING will be treated as an elementary alphanumeric data item, and, when moved to a numeric item, as an unsigned integer. Without careful reading, one might infer decimal alignment from your statement. I still contend that this is so arcane that a prudent programmer will avoid this construct.

WRT POINTER, COUNT and TALLYING, I entirely agree. The UNSTRING statement, though a bit clumsy in its syntax, is quite feature-rich.

Tom Morrison
 
I'm a bit confused by your problem stmt. It may result from your attempt to &quot;take the problem in little pieces&quot;. I like that approach but it can cause problems, in that the final problem may, at times, bare no resemblance to the early statements. The result is a bunch of code that has to be abandoned.

What makes me think this may happen is that you show a file with fixed length fields but use &quot;unstring&quot; to move them. Since you describe a CSV (comma separated values/variables) file, I tend to think the ultimate file may contain variable length fields.

One of the primary dictums of pgming is &quot;know your input&quot;. It may be helpful for you to study the &quot;live&quot; input and give us a representative sample. If it turns out to be truly fixed fields, a series of good old moves is the ticket. If, on the other hand, the fields are variable in length, you've got a few problems to deal with:

1) Variable length records, where the lengths of the records can vary unpredictably.
2) The possibility of embedded commas (,) in the A/N fields.
3) The presence (or absence) of decimal pts (.), and/or commas (,) and/or spaces in the numeric field.
4) The numeric field can look like &quot;1324.00&quot; in one rec, and &quot;14&quot; in another, and &quot; 6 &quot; in a 3rd.

HTH, Jack.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top