Crash Course Delphi 15 [beta]:
CSV Files - part 2

(Continued in Lesson 16)


Parsing a CSV file


About loading and parsing a csv file

(text still to be polished and images to be added, but all source code has been tested)

Setup of the project

Create a new directory, for example C:\ParseCSV

Create a small database to keep our stock of office material. The file format should follow the rules as explained in lesson 14. Set up the following structure, either with MS Excel (see last part of lesson 14) or with a text editor, and save as Office.csv in directory C:\ParseCSV

Partnumber,Article,Price,Stock
12005A,Calculator,20.49,26
12005B,"Calculator Pro",30.49,10
12006A,PC,990.00,6
12007A,Scanner,349.49,7

  • Each record is one line in the text file Office.csv
  • The first record is a header record, containing the field names. This is not needed by the rules for CSV, but it's easier for knowing who's who :)
  • The fields are separated by commas.
  • Fields that contain spaces are delimited with double-quotes.

Set up a new Delphi project in C:\ParseCSV, with just one form, and save the project as ParseCSV.dpr

Drop the following components on the form and set them up as follows:

  • MainMenu1:
    •  add an item to MainMenu1: Caption: &File ; Name: MenuFile
    •  add two items under MenuFile:
      • Caption: &Load , Name: FileLoad
      • Caption: E&xit , Name: FileExit
  • Listbox1
  • SG1 (StringGrid1):
    • ColCount: 4
    •  FixedCols: 0
    •  FixedRows: 1 (for the field names)
    • RowCount: 2

Analysis

What should the OnClick event handler of FileLoad do?

  1. Let the user select a CSV file.
  2. Load the selected file into the listbox.
  3. Set the number of rows of the stringgrid equal to the number of records. That is, the number of lines in the CSV file, thus: the number of items in the listbox.
  4. Split up each item of the listbox into smaller strings, the field values. The technical term is: we "parse" the record-strings. Next, put every field value into the corresponding cell of the stringgrid. For keeping with good modular coding practices, we'll delegate these two tasks to a separate routine, that we named ParseRecord.
  5. Select the first "data" cell of the stringgrid at column 0 / row 1.

What should ParseRecord do with a string (i.e. a record) that it receives?

(To make things not too complicated, let's assume that there are no double quotes nor commas embedded in the field values. In a next version, we'll design a more complete algorithm.)

  1. Remove all the double quotes.
  2. Find the position of the first comma.
  3. Extract the first field value from the record-string.
  4. Put the field value in the corresponding cell of the stringgrid.
  5. If more fields, then delete from the record-string: the extracted field plus its trailing comma.
  6. If more fields, then repeat from step (2).

And finally, the OnClick event handler of FileExit should simply stop the application. As you remember, this is done by closing its main window (its only window in this case).

Let's code

procedure TForm1.FileLoadClick(Sender: TObject);
var
  FileName1, sRecord: string;
  Row: integer;
begin
  // Let user select a file. 
  // Skip this until next lesson. For now, simply hard-code it.
  FileName1 := 'C:\ParseCSV\Office.csv';

  ListBox1.Items.LoadFromFile(FileName1);  // 2.
  SG1.RowCount := ListBox1.Items.Count;    // 3.

  // for every record... ( count starts at 0 ! )
  for Row := 0 to ListBox1.Items.Count - 1 do begin  
    sRecord := ListBox1.Items[Row];
    ParseRecord(sRecord, Row);             // 4.  
  end;

  // 5. Select first "data" cell  
  SG1.Row := 1;
  SG1.Col := 0;
  SG1.SetFocus;
end;


The procedure ParseRecord should be declared under Private in the Interface section of the form:

  private
    procedure ParseRecord(sRecord: string; Row: integer);

Here is the code that comes in the implementation part:
procedure TForm1.ParseRecord(sRecord: string; Row: integer);
var
  Col, PosComma: integer;
  sField: string;
begin
  sRecord := StringReplace(sRecord, '"', '', 
                           [rfReplaceAll]    ); // 1.
  Col := 0;    // first column of stringgrid
  repeat
    PosComma := Pos(',', sRecord);              // 2. 
    if PosComma > 0 then
      sField := Copy(sRecord, 1, PosComma - 1)  // 3.a
    else
      sField := sRecord;                        // 3.b 
    SG1.Cells[Col, Row] := sField;              // 4.
    if PosComma > 0 then begin                  // 5. 
      Delete(sRecord, 1, PosComma);             
      Col := Col + 1;                           // next column
    end;
  until PosComma = 0;                           // 6.
end;

Finally, the code closing our application:

procedure TForm1.FileExitClick(Sender: TObject);
begin
  Close;  // close main window of application
end;


As you see, we don't let the user select a file just yet, we hard coded for one particular file. The file selection code is discussed in a next lesson.

« Lesson 14  Lesson 16 »     Top