0

I have Perl and CSV file with something like:

"Name","Lastname"
"Homer","Simpsons"
"Ned","Flanders"

In this CSV file I have header in the first line and in other lines there are data.

I want to convert this CSV file to such Perl data:

[
    {
        Lastname => "Simpsons",
        Name     => "Homer",
    },
    {
        Lastname => "Flanders",
        Name     => "Ned",
    },
]

I've written the function that users Text::CSV and doing what I need. Here is the sample script:

#!/usr/bin/perl

use strict;
use warnings FATAL => 'all';
use 5.010;
use utf8;
use open qw(:std :utf8);

use Text::CSV;

sub read_csv {
    my ($filename) = @_;

    my @first_line;
    my $result;

    my $csv = Text::CSV->new ({ binary => 1, auto_diag => 1 });
    open my $fh, "<:encoding(utf8)", $filename or die "$filename: $!";
    while (my $row = $csv->getline ($fh)) {
        if (not @first_line) {
            @first_line = @{$row};
        } else {
            push @{$result}, { map { $first_line[$_] => $row->[$_] } 0..$#first_line };
        }
    }
    close $fh;

    return $result;
}

my $data = read_csv('sample.csv');

This works fine but this function I want to use in several scripts. I'm greatly suprised that Text::CSV doesn't have this feature.

My question. What should I do to simplify solving such tasks in the future for me and others?

Should I use some Perl module from CPAN, should I try to add this function to Text::CSV, or something else?

2
  • I'd contact the author of Text::CSV and ask if he'd accept a patch. If you create your own module, you'll be sole responsible for keeping it up to date. Judging from the list of authors, it seems that the module is being actively maintained. Commented Jun 26, 2013 at 10:47
  • Regardless of if you put it on the CPAN, do you know how to create pacakges and how they work, or are you looking more for the right thing to do, and not how to do it? Commented Jun 26, 2013 at 10:49

2 Answers 2

3

Huh? Why so complicated? First, we fetch the header outside of the loop:

my $headers = $csv->getline($fh) or die "no header";

Assign these to be the column names:

$csv->column_names(@$headers);

Then, each call to getline_hr will provide a hashref:

while (my $hashref = $csv->getline_hr($fh)) {
  push @$result, $hashref;
}

We can also use getline_hr_all:

$result = $csv->getline_hr_all($fh);

In other words, it ain't complex, most pieces are already provided by Text::CSV, and it can be done in very few lines.

Also, a module like this seems to already exist: Text::CSV::Slurp. (note: reverse dependency search through metacpan is awesome)

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the idea to use reverse dependency in metacpan. I've knew about that feature, but I didn't realized to use it in this question. Yes, usage of the existing module is the best possible choice.
0

It's probably not a standard feature because different people will want their CSV files parsed into different data structures.

Why not create your own module that wraps this function?

package CSVRead;

use strict;
use warnings;
use 5.010;
use open qw(:std :utf8);

use Text::CSV;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(read_csv);

sub read_csv {
    my ($filename) = @_;

    my @first_line;
    my $result;

    my $csv = Text::CSV->new ({ binary => 1, auto_diag => 1 });
    open my $fh, "<:encoding(utf8)", $filename or die "$filename: $!";
    while (my $row = $csv->getline ($fh)) {
        if (not @first_line) {
            @first_line = @{$row};
        } else {
            push @{$result}, { map { $first_line[$_] => $row->[$_] } 0..$#first_line };
        }
    }
    close $fh;

    return $result;
}

Then, use it like this:

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

use Data::Dumper;
use CSVRead;

my $data = read_csv('sample.csv');

say Dumper $data;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.