Cutting Fields From A CSV File

December 7, 2021

Over at Stack Overflow, I answered a question about cutting fields from a CSV file. Paraphrasing:

A file in CSV format has a header row containing field names followed by record rows containing actual data. The user wants to cut fields from the CSV file to create a new CSV file containing only the specified fields, specifying the fields by name instead of using their ordinal position.

Your task is to write a program to cut fields from a CSV file by name. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Pages: 1 2

2 Responses to “Cutting Fields From A CSV File”

  1. Using Pascal:

    program CSVSplitter;

    {$APPTYPE CONSOLE}
    {$R *.res}

    uses
    System.SysUtils, Classes;

    procedure Split(inputFileName, fieldName, outputFileName: String);
    var
    inputFile, outputFile: TextFile;
    header, line: String;
    columnList: TStringList;
    index: Integer;
    begin
    AssignFile(inputFile, inputFileName);
    columnList := TStringList.Create;
    try
    Reset(inputFile);
    if Not Eof(inputFile) then
    Readln(inputFile, header);

    columnList.CommaText := UpperCase(header);
    index := columnList.IndexOf(UpperCase(fieldName));
    if index >= 0 then
    begin
      AssignFile(outputFile, outputFileName);
      try
        ReWrite(outputFile);
        writeln(outputFile, fieldName);
    
        while Not Eof(inputFile) do
        begin
          Readln(inputFile, line);
          columnList.CommaText := line;
          writeln(outputFile, columnList[index]);
        end;
      except
        on E: Exception do
        begin
          writeln('Cannot write to file ' + outputFileName + ' -> ' + E.Message);
        end;
      end;
    end
    else
      writeln('Field ' + fieldName + ' cannot be found in file ' + inputFileName);
    

    except
    on E: Exception do
    begin
    writeln('Exception occurs during reading file ' + inputFileName + ' -> ' + E.Message);
    end;
    end;
    columnList.Free;
    CloseFile(inputFile);
    CloseFile(outputFile);
    end;

    begin
    if ParamCount = 3 then
    begin
    if FileExists(ParamStr(1)) then
    begin
    Split(ParamStr(1), ParamStr(2), ParamStr(3));
    end
    else
    writeln('File ' + ParamStr(1) + ' cannot be found.');
    end
    else
    writeln('Usage: ' + ExtractFileName(ParamStr(0)) + ' ');
    end.

  2. Richard A. O'Keefe said

    I found the use of the word “cut” and “field” instead of, say, “select” and “column”, confusing.
    Using Smalltalk, with my own CSV library, I’ve lightly tested this:

      (CSVDecoder on: StdIn) bindOwn: [:input |
        |header inverse map row|
        header := input next.
        inverse := Dictionary new: header size.
        header keysAndValuesDo: [:index :name |
          inverse at: name put: index].
        map := arguments collect: [:name | inverse at: name].
        row := Array new: map size.
        (CSVEncoder on: StdOut) bindOwn: [:output |
          output nextPut: arguments.
          input do: [:each |
            map keysAndValuesDo: [:index :origin |
              row at: index put: (each at: origin)].
            output nextPut: row]]].
    

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: