Search code examples
perlcsvperl-module

Retrieve first row from CSV as headers using Text::CSV


I feel like I'm missing something rather obvious, but can't find any answers in the documentation. Still new to OOP with Perl, but I'm using Text::CSV to parse a CSV for later use.

How would I go about extracting the first row and pushing the values to array @headers?

Here's what I have so far:

#!/usr/bin/perl
use warnings;
use diagnostics;
use strict;
use Fcntl ':flock';
use Text::CSV;

my $csv = Text::CSV->new({ sep_char => ',' });
my $file = "sample.csv";
my @headers;        # Column names

open(my $data, '<:encoding(utf8)', $file) or die "Could not open '$file' $!\n";
while (my $line = <$data>) {
  chomp $line;

  if ($csv->parse($line)) {             
    my $r = 0;      # Increment row counter
    my $field_count = $csv->fields();       # Number of fields in row

    # While data exists...
    while (my $fields = $csv->getline( $data )) {
      # Parse row into columns
      print "Row ".$r.": \n";    

      # If row zero, process headers
      if($r==0) {
        # Add value to @columns array
        push(@headers,$fields->[$c]);
      } else {
        # do stuff with records...
      }         
  }
  $r++
}           
close $data;

You'd think that there would be a way to reference the existing fields in the first row.


Solution

  • Pretty much straight from the documentation, for example.

    #!/usr/bin/perl
    use strict;
    use warnings;
    use Text::CSV_XS;
    
    my $csv = Text::CSV_XS->new ({ binary => 1, eol => $/ });
    
    my $file = 'o33.txt';
    open my $io, "<", $file or die "$file: $!";
    
    my $header = $csv->getline ($io);
    print join("-", @$header), "\n\n";
    
    while (my $row = $csv->getline ($io)) {
        print join("-", @$row), "\n";
    }
    
    __END__
    ***contents of o33.txt
    lastname,firstname,age,gender,phone
    mcgee,bobby,27,M,555-555-5555
    kincaid,marl,67,M,555-666-6666
    hofhazards,duke,22,M,555-696-6969
    

    Prints:

    lastname-firstname-age-gender-phone
    
    mcgee-bobby-27-M-555-555-5555
    kincaid-marl-67-M-555-666-6666
    hofhazards-duke-22-M-555-696-6969
    

    Update: Thinking about your problem, it may be that you want to address the data by its column name. For that, you might be able to use something (also from the docs), like this:

    $csv->column_names ($csv->getline ($io));
    
    while (my $href = $csv->getline_hr ($io)) {
        print "lastname is: ", $href->{lastname},
              " and gender is: ", $href->{gender}, "\n"
    }
    

    Note: You can use Text::CSV instead of Text::CSV_XS, as the former is a wrapper around the latter.