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

10,805

Solution 1

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.

Solution 2

Thought I'd post my results for others.

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

sub read_csv {  
    my $csv = Text::CSV->new({ sep_char => ',' });
    my $file = shift;

    open(my $data, '<:encoding(utf8)', $file) or die "Could not open '$file' $!\n";

    # Process Row Zero
    my $header = $csv->getline ($data);
    my $field_count = $csv->fields();

    # Read the rest of the file
    while (my $line = <$data>) {
        chomp $line;

        # Read line if possible
        if ($csv->parse($line)) {             
            my $r = 0;

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

                # Print column values
                for(my $c=0; $c<@$fields; $c++) {
                    print @$header[$c]." : ".@$fields[$c]."\n";
                }
                $r++                                                        
            }
        }
        close $data;
    }
}

Cheers

Share:
10,805
Ryan Dunphy
Author by

Ryan Dunphy

Always learning, always optimizing, always automating.

Updated on July 25, 2022

Comments

  • Ryan Dunphy
    Ryan Dunphy almost 2 years

    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.

  • Chris Charley
    Chris Charley over 10 years
    Your first while loop, while (my $line = <$data>) reads in the first data line but does not print it out. Only the second while loop should be used instead.