CW73
CW73

Reputation: 1

Perl CSV Parsing with Header Access - header on row 3 and only some rows instead of all rows

I am trying to parse a given CSV File, stream on regular base.

My requirement is to Access the Data via ColumName (Header). The ColumNames are not given in row 1. The ColumNames are given in row 2. The CSV does have 100 rows but I only need 2 data rows to import. The separator is a tab.

The following script works for header at row 1 and for all rows in the file I failed to modify it to header at row 2 and to use only 2 rows or a number of rows.

script:

#!/usr/bin/perl
use strict;
use warnings;
use Tie::Handle::CSV;
use Data::Dumper;





my $file = "data.csv";
my $fh = Tie::Handle::CSV->new ($file, header => 1, sep_char => "\t");
my $hfh = Tie::Handle::CSV->new ($file, header => 0, sep_char => "\t");

my $line = <$hfh>;
my $myheader;


while (my $csv_line = <$fh>)
{

        foreach(@{$line}) 
        {
                if ( $_ ne "" )
                {
                        print $_ . "=" .   $csv_line->{$_} . "\n" ;
                }
        }


}

The Data.csv could look like:

This is a silly sentence on the first line
Name    GivenName   Birthdate   Number
Meier   hans    18.03.1999  1
Frank   Thomas  27.1.1974   2
Karl    Franz   1.1.2000    3
Here could be something silly again

Thanks for any hint.

best regards

Upvotes: 0

Views: 180

Answers (4)

CW73
CW73

Reputation: 1

thanks got it running with "keys %$csv_line". I was not using because of missing knowlegde. ;-)

#!/usr/bin/perl
use strict;
use warnings;
use Tie::Handle::CSV;


my $file = "data.csv";

open (my $secfile, '<',$file) or die "can't open file $file: $!\n";
<$secfile>;
my $fh = Tie::Handle::CSV->new ($secfile, header => 1, sep_char => "\t");


my $numberoflines = 3 ;

while ($numberoflines-- )
{
        my $csv_line = <$fh> ;
        my @Columns = keys %{ $csv_line } ;
        foreach (@Columns )      
        {
                if ( $_ ne "" )
                {
                        print $_ . "=" .   $csv_line->{$_} . "\n" ;
                }
        }
        print "-----------\n"


}

On last question: The File I Read will be filled and modified by an other program. What can I do to detect the File violation in case it makes a problem. And I dont what the my script dies.

Thanks regards

Upvotes: 0

CW73
CW73

Reputation: 1

thanks to you both.

To clarify more detail my requirements.

The original Data File does have maybe 100 Colums with dynamic unknown Names for me. I will create a list of Colums/Attribute from a other Service for which this script should provide the data content of some rows.

Request is in Terms of the data example: Please provide all Names and all Birthdates of the first 25 Rows. The next Request could be all Names and Givennames of the first 10 rows.

That means from the content of 100 Columns I have to provide the content for two, four, five Columns only.

The output I use (foreach), is only to test the Access by ColumName to the content of rows.

I mixed up your solution and stayed with Tie::Handle::CSV.

At the moment I have to use the two filehandles- Maybe you have a hint to be more effective.

#!/usr/bin/perl
use strict;
use warnings;
use Tie::Handle::CSV;
use Data::Dumper;





my $file = "data.csv";

open (my $infile, '<',$file) or die "can't open file $file: $!\n";
open (my $secfile, '<',$file) or die "can't open file $file: $!\n";
<$infile>; # skip first line
<$secfile>;


my $fh = Tie::Handle::CSV->new ($secfile, header => 1, sep_char => "\t");
my $hfh = Tie::Handle::CSV->new ($infile, header => 0, sep_char => "\t");

my $line = <$hfh>;

my $numberoflines = 2 ;

while ($numberoflines-- )
{
        my $csv_line = <$fh> ;

        foreach(@{$line})
        {
                if ( $_ ne "" )
                {
                        print $_ . "=" .   $csv_line->{$_} . "\n" ;
                }
        }


}

Upvotes: 0

clamp
clamp

Reputation: 3262

Tie::Handle::CSV accepts a filehandle instead of a filename. You can skip the first line by reading one line from it before you pass the filehandle to Tie::Handle::CSV:

use strict;
use warnings;
use Tie::Handle::CSV;
use Data::Dumper;

my $file = "data.csv";

open (my $infile, '<',$file) or die "can't open file $file: $!\n";
<$infile>; # skip first line
my $hfh = Tie::Handle::CSV->new ($infile, header => 1, sep_char => "\t");

my @csv;
my $num_lines = 3;
while ($num_lines--){
    my $line = <$hfh>;
    push @csv, $line;
}
print Dumper \@csv;

Upvotes: 1

Shawn
Shawn

Reputation: 52384

Use Text::CSV_XS instead of Tie::Handle::CSV (Which depends on the module so you have it installed already), read and throw away the first line, use the second line to set column names, and then read the rest of the data:

#!/usr/bin/env perl
use warnings;
use strict;
use feature qw/say/;
use Text::CSV_XS;

my $csv = Text::CSV_XS->new({ sep => ",", # Using CSV because TSV doesn't play well with SO formatting
                              binary => 1});

# Read and discard the first line
$_ = <DATA>;

# Use the next line as the header and set column names
$csv->column_names($csv->getline(*DATA));

# Read some rows and access columns by name instead of position
my $nr = 0;
while (my $record = $csv->getline_hr(*DATA)) {
    last if ++$nr == 4;
    say "Row $nr: $record->{GivenName} was born on $record->{Birthdate}";
}

__DATA__
This is a silly sentence on the first line
Name,GivenName,Birthdate,Number
Meier,hans,18.03.1999,1
Frank,Thomas,27.1.1974,2
Karl,Franz,1.1.2000,3
Here could be something silly again

Upvotes: 2

Related Questions