bones07 has asked for the wisdom of the Perl Monks concerning the following question:

Hi all, This is my first time dealing with CSV's in perl and I'm having some trouble. I have 2 CSV files which have the same columns. The issue I'm trying to tackle is that the first CSV file has data in a certain column that is blank in the second file. The first column is a list of filenames, and the 12th column in the file is an ID number for the corresponding file. So far, I'm taking in the first CSV file and making a hash of filenames / ID numbers. My thought was simply to read in the second file, run a match again the filenames in column 1, and then reference the hash I've created to get the ID number for that file name. Then I would write that ID number into column 12 on the second file within the same row as the filename I'm referencing. I just cant seem to work the logic to reference and then write the data. Any ideas? Thanks in advance. What I have so far for code follows:
#!/usr/bin/perl use Text::CSV; $file = 'testfile.csv'; my $csv = Text::CSV->new(); #Bring in our csv, parse it, and make a hash of filenames (keys) and I +D numbers (values) open (CSV, "<", $file) or die $!; my @content; %masterlist; while (<CSV>){ next if ($. == 1); if ($csv->parse($_)){ my @columns = $csv->fields(); $masterlist{"$columns[0]"} = "$columns[11]"; }else{ my $err = $csv->error_input; print "Failed to parse line: $err"; } } close CSV; # Invert the array twice to get rid of any duplicates that may have go +tten into our hash %masterlist = reverse %masterlist; %masterlist = reverse %masterlist; #Show us the output to make sure the keys and values are lined up corr +ectly foreach $key ( keys %masterlist ) { print $key, " => ", $masterlist{$key}, "\n"; }

Replies are listed 'Best First'.
Re: Please help with CSV
by GrandFather (Saint) on Apr 14, 2011 at 23:55 UTC

    It may be that you are looking for something like this:

    #!/usr/bin/perl use strict; use warnings; use Text::CSV; my $file1 = <<FILE1; number,letter,both 1,a,1a 2,b,2b 3,c,3c FILE1 my $file2 = <<FILE2; number,letter,both 1,a,1a 2,,2b 3,c,3c FILE2 my $csv = Text::CSV->new(); my %masterlist; open my $f1In, "<", \$file1; <$f1In>; # Skip header row while (<$f1In>) { if ($csv->parse($_)) { my @columns = $csv->fields(); $masterlist{$columns[0]} = $columns[1]; } else { my $err = $csv->error_input; print "Failed to parse line $. in file1: $err"; } } close $f1In; open my $f2In, "<", \$file2; <$f2In>; # Skip header row while (<$f2In>) { if ($csv->parse($_)) { my @columns = $csv->fields(); $columns[1] = $masterlist{$columns[0]} if ! length $columns[1] +; print join (',', @columns), "\n"; } else { my $err = $csv->error_input; print "Failed to parse line $. in file1: $err"; } } close $f1In;

    Prints:

    1,a,1a 2,b,2b 3,c,3c
    True laziness is hard work
Re: Please help with CSV
by Tux (Canon) on Apr 15, 2011 at 05:53 UTC

    You've quite obviously already taken the time to come up with the code, and though this looks quite good for you current case, this will break if your CSV data gets more complicated like having UTF8 encoded data or embedded newlines, this approach will break. I'd advice you to use the more safe way (note that I did not change anything else, see GrandFathers answer for changes). I have commented all my changes:

    my $csv = Text::CSV->new ({ binary => 1, # Allow utf8 and embedded newlines auto_diag => 1, # make detecting CSV errors easy }); # open into a lexical file handle open my $fh, "<", $file or die "$file: $!"; my @content; my %masterlist; $csv->getline ($fh); # skip first line # @hdr = @{$csv->getline ($fh)}; would save it for header info # $csv->getline () respects $/, but reads past embedded newlines while (my $row = $csv->getline ($fh)) { $masterlist{$row->[0]} = $row->[1]; # auto_diag takes care of the failures } close $fh;

    See how much shorter that also gets?


    Enjoy, Have FUN! H.Merijn