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 IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Create a CSV Record 3

Status
Not open for further replies.

BrianTyler

IS-IT--Management
Jan 29, 2003
232
GB
I have been using Cobol for nearly over 35 years, and I am still amazed at the short-sightedness of the language developers. (My biggest gripe has always been the handling of dates - by now there should be a field type for dates, and data arithmetic).

My current problem is the creation of a CSV style of record from a number of data items, many of which have trailing spaces. Obviously, I could STRING all of the items together into a character array, and then have a clever indexing routine to shuffle up the data, removing spaces (I'll live with leading zeros).

Has anyone a good solution to this problem.

I am using Cobol-85 on AIX.

Brian
 
Hi, I have been using this for years.
Bob

000060 FD CSV-file
RECORD IS VARYING IN SIZE
FROM 10 TO 302 CHARACTERS
DEPENDING ON CHARACTERSPLUS2
000063 LABEL RECORDS ARE std 000064 DATA RECORD IS CSV-REC.
000065 01 CSV-REC.
000066 05 PIC X(302).


01 CHARACTERSPLUS2 PIC 999.
01 CSV-IMAGE.
05 FILLER PIC X(500) VALUE SPACES.
01 CSV-AREA REDEFINES CSV-IMAGE.
05 CSV PIC X OCCURS 500.

perform do-csv thru do-csv-exit.

DO-CSV.
STRING '"' DELIMITED BY SIZE
RENT-SEQ DELIMITED BY SIZE
'","' DELIMITED BY SIZE
RENT-NKY DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-NAME DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-CO DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-2ND DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-STRT DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-CITY DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-ST DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-ZIP DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-COUNTRY DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-PJ DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-INFO DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-TELE DELIMITED BY SIZE
'","' DELIMITED BY SIZE
RENT-PREFIX DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-FNAME DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-MID DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-LNAME DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-SUFFIX DELIMITED BY " "
'","' DELIMITED BY SIZE
RENT-TITLE DELIMITED BY " "
'"' DELIMITED BY SIZE INTO CSV-AREA
ON OVERFLOW DISPLAY "HELP".
MOVE 500 TO CHARACTERSPLUS2.
PERFORM COUNT-DOWN THRU COUNT-DOWN-EXIT.
MOVE CSV-IMAGE TO CSV-REC.
WRITE CSV-REC.
MOVE SPACES TO CSV-REC.
MOVE SPACES TO CSV-IMAGE.
DO-CSV-EXIT.
EXIT.
COUNT-DOWN.
IF CSV (CHARACTERSPLUS2) NOT = " "
GO TO COUNT-DOWN-EXIT.
IF CHARACTERSPLUS2 = ZEROES GO TO DO-CSV-EXIT.
SUBTRACT 1 FROM CHARACTERSPLUS2.
GO TO COUNT-DOWN.
COUNT-DOWN-EXIT.
EXIT.

 
Hi all,

Brian is probably long gone by now, but I'd like to caution those who read this thread looking for a solution to their CSV problem.

Make sure the solutions offered here (or anywhere else) can handle all the possible data configurations you may encounter in your input. If you're creating the CSV file you must program for them as well.

How do you handle:

Fields that contain commas. The field is usually encased in quotes, e.g. "12,000.00".

Which leads us to the next ques. How are quotes represented in a data field?

Variable length I/P or O/P?

The best thing to do is to create test data conditions in the same environment used by the sender/receiver and study the CSV O/P.

Don't forget to create first/last/consecutive char conditions, e.g.:

"""harvey""""
"harvey""
""har"vey"

You can try the same kinds of things w/commas but they're generally more straight forward.



Regards, Jack.

"A problem well stated is a problem half solved" -- Charles F. Kettering
 
Inspect function reverse can inspect the number of blank spaces on the end and then you can use that figure to determine using subscripting i.e. move field (1:variable) to move part of a field. I developed my own way of handling addresses which were stored in one large field.

If you do not like my post feel free to point out your opinion or my errors.
 
A good idea. This is probably pointing towards the least messy solution so far.

This will work for most of my cases, the only ones still likely to require adjustment are fields with embedded quotes and those with embedded commas. If these are likely to occur, further inspects etc will be required.

Brian
 
Hi guys,

I'm just new to this group. Thought this might help you in some way though.

Below is a sample of the codes which I have been using for converting fixed length records to csv format.

Henri.....

WORKING-STORAGE SECTION.

01 CSV-WORK-AREA.
05 CSV-INPUT-AREA PIC X(40) VALUE SPACES.
05 CSV-INPUT-AREA-SIZE PIC 9(02) VALUE ZEROES.
05 LEADING-SPACES-COUNT PIC 9(02) VALUE ZEROES.
05 TRAILING-SPACES-COUNT PIC 9(02) VALUE ZEROES.
05 DATA-LENGTH PIC 9(02) VALUE ZEROES.
05 DELIMITER-INDICATOR PIC 9(02) VALUE ZEROES.
88 DATA-HAS-DELIMITER VALUES 1 THRU 99.
05 CSV-DELIMITER PIC X(01) VALUE ",".
05 DOUBLE-QUOTE PIC X(01) VALUE '"'.
05 START-OF-DATA-PTR PIC 9(02) VALUE ZEROES.
05 CSV-INSERT-POSITION PIC 9(02) VALUE ZEROES.
05 CSV-RECORD PIC X(100) VALUE SPACES.

01 DATA-SOURCE.
05 RECORD-1.
10 FILLER PIC X(02) VALUE "A1".
10 FILLER PIC 9(05) VALUE 1111.
10 FILLER PIC X(10) VALUE "John Rae".
10 FILLER PIC X(10) VALUE "Doe".
10 FILLER PIC X(25) VALUE "14 Apt 123 Unknown St.".
10 FILLER PIC X(12) VALUE "Any City".
10 FILLER PIC X(03) VALUE "YZ".
10 FILLER PIC X(06) VALUE " ".

05 RECORD-2.
10 FILLER PIC X(02) VALUE " ".
10 FILLER PIC 9(05) VALUE 2222.
10 FILLER PIC X(10) VALUE "Jane".
10 FILLER PIC X(10) VALUE "Day".
10 FILLER PIC X(25) VALUE " 87 Which St, Unit 10".
10 FILLER PIC X(12) VALUE "What City".
10 FILLER PIC X(03) VALUE "UX".
10 FILLER PIC X(06) VALUE "A1B2C3".

01 RECORD-MAP.
10 RM-CATEGORY PIC X(02).
10 RM-ID-NUMBER PIC 9(05).
10 RM-FIRSTNAME PIC X(10).
10 RM-LASTNAME PIC X(10).
10 RM-ADDRESS PIC X(25).
10 RM-CITY PIC X(12).
10 RM-STATE PIC X(03).
10 RM-ZIP PIC X(06).


PROCEDURE DIVISION.

PROGRAM-LOGIC SECTION.

MOVE RECORD-1 TO RECORD-MAP.
PERFORM CREATE-CSV-RECORD.

MOVE RECORD-2 TO RECORD-MAP.
PERFORM CREATE-CSV-RECORD.

STOP RUN.


CREATE-CSV-RECORD SECTION.

DISPLAY "FIX: " RECORD-MAP.

INITIALIZE CSV-RECORD
CSV-INSERT-POSITION.

MOVE RM-CATEGORY TO CSV-INPUT-AREA.
PERFORM CONVERT-TO-CSV-FORMAT.

MOVE RM-ID-NUMBER TO CSV-INPUT-AREA.
PERFORM CONVERT-TO-CSV-FORMAT.

MOVE RM-FIRSTNAME TO CSV-INPUT-AREA.
PERFORM CONVERT-TO-CSV-FORMAT.

MOVE RM-LASTNAME TO CSV-INPUT-AREA.
PERFORM CONVERT-TO-CSV-FORMAT.

MOVE RM-ADDRESS TO CSV-INPUT-AREA.
PERFORM CONVERT-TO-CSV-FORMAT.

MOVE RM-CITY TO CSV-INPUT-AREA.
PERFORM CONVERT-TO-CSV-FORMAT.

MOVE RM-STATE TO CSV-INPUT-AREA.
PERFORM CONVERT-TO-CSV-FORMAT.

MOVE RM-ZIP TO CSV-INPUT-AREA.
PERFORM CONVERT-TO-CSV-FORMAT.

DISPLAY "CSV: " CSV-RECORD.


CONVERT-TO-CSV-FORMAT SECTION.

PARSE-CSV-INPUT-AREA.

INITIALIZE CSV-INPUT-AREA-SIZE
DELIMITER-INDICATOR
LEADING-SPACES-COUNT
TRAILING-SPACES-COUNT
START-OF-DATA-PTR
DATA-LENGTH.

IF CSV-INPUT-AREA NOT = SPACES
* Check for delimiter
INSPECT CSV-INPUT-AREA
TALLYING DELIMITER-INDICATOR FOR ALL CSV-DELIMITER
* get data length
INSPECT CSV-INPUT-AREA
TALLYING LEADING-SPACES-COUNT FOR LEADING SPACES
INSPECT CSV-INPUT-AREA
TALLYING TRAILING-SPACES-COUNT FOR TRAILING SPACES
COMPUTE CSV-INPUT-AREA-SIZE = FUNCTION LENGTH(CSV-INPUT-AREA)
COMPUTE DATA-LENGTH = CSV-INPUT-AREA-SIZE
- LEADING-SPACES-COUNT
- TRAILING-SPACES-COUNT
END-IF.

POST-CSV-DATA.
* need to do this in case first field encountered is blank
IF CSV-INSERT-POSITION = 0
MOVE 1 TO CSV-INSERT-POSITION
ELSE
MOVE CSV-DELIMITER TO CSV-RECORD(CSV-INSERT-POSITION:1)
ADD 1 TO CSV-INSERT-POSITION.

IF DATA-LENGTH > 0
* insert a double quote if the string has an embedded comma
IF DATA-HAS-DELIMITER
MOVE DOUBLE-QUOTE TO CSV-RECORD(CSV-INSERT-POSITION:1)
ADD 1 TO CSV-INSERT-POSITION
END-IF
COMPUTE START-OF-DATA-PTR = LEADING-SPACES-COUNT + 1
MOVE CSV-INPUT-AREA(START-OF-DATA-PTR:DATA-LENGTH)
TO CSV-RECORD(CSV-INSERT-POSITION:DATA-LENGTH)
ADD DATA-LENGTH TO CSV-INSERT-POSITION
IF DATA-HAS-DELIMITER
MOVE DOUBLE-QUOTE TO CSV-RECORD(CSV-INSERT-POSITION:1)
ADD 1 TO CSV-INSERT-POSITION
END-IF
END-IF.

CONVERT-TO-CSV-FORMAT-EXIT.
EXIT.



 
Hi henrimercado

You have to check olso in the string DOUBLE-QUOTE, like the string ymc"a will have: "ymc""a"

Barry
 
Hi baruch,

Thanks for pointing this out. Didn't realize that the codes that I picked up didn't check for the double quotes.

Anyways, here is the code that I used to cater for double quotes:

Instead of the statements....
MOVE CSV-INPUT-AREA(START-OF-DATA-PTR:DATA-LENGTH)
TO CSV-RECORD(CSV-INSERT-POSITION:DATA-LENGTH)
ADD DATA-LENGTH TO CSV-INSERT-POSITION

I used ....
PERFORM WITH TEST AFTER
VARYING DATA-IDX FROM START-OF-DATA-PTR BY 1
UNTIL DATA-IDX > DATA-LENGTH
IF CSV-INPUT-AREA(DATA-IDX:1) = DOUBLE-QUOTE
MOVE DOUBLE-QUOTE TO CSV-RECORD(CSV-INSERT-POSITION)
ADD 1 TO CSV-INSERT-POSITION
END-IF
MOVE CSV-INPUT-AREA(DATA-IDX:1)
TO CSV-RECORD(CSV-INSERT-POSITION)
ADD 1 TO CSV-INSERT-POSITION
END-PERFORM



Alternatively, if a programmer feels that there is a difference in their processing time only by using the PERFORM VAYING routine, then they may utilize both routines by checking first if the string contains a double quote using INSPECT then use the PERFORM VARYING if it does, or otherwise use the one with the MOVE statement . Though I didn't really bother much about this.

Regards,

Henri....

 
Forgot to mention earlier that the double quote of course should also be covered in the statetement "DATA-HAS-DELIMITER".

Regards,

Henri....

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top