Coder Social home page Coder Social logo

text-csv's Introduction

Text::CSV version 1.33

Text::CSV provides facilities for the composition and decomposition of comma-separated values. An instance of the Text::CSV class can combine fields into a CSV string and parse a CSV string into fields.

The module accepts either strings or files as input and can utilize any user-specified characters as delimiters, separators, and escapes so it is perhaps better called ASV (anything separated values) rather than just CSV.

Please refer to the complete documentation of Text::CSV for more information.

Installation

cpanm Text::CSV

Or manually:

perl Makefile.PL
make
make test
make install

Copyright and License

Copyright (C) 1997 Alan Citterman. All rights reserved. Copyright (C) 2007-2015 Makamaka Hannyaharamitu. All rights reserved.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

text-csv's People

Contributors

anirvan avatar bugfood avatar charsbar avatar dsteinbrunner avatar garu avatar hiratara avatar ktat avatar kyzn avatar makamaka avatar mohawk2 avatar shlomif avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

text-csv's Issues

Can't write non-ASCII symbols

Please check an example

my $file = "test.csv";
my $csv = Text::CSV->new({ eol => "\n" }) or die "Cannot use CSV: ".Text::CSV->error_diag ();
open my $fh, ">", $file or die "$file.csv: $!";
my $a = [ 'a', 'б' ];
$csv->print($fh, $a);
close $fh or die "$!";

is working and produces

$ cat test.csv 
a,b

But if we try to write non-ASCII symbols like

my $a = [ 'a', 'б' ];
$csv->print($fh, $a);

output csv will empty

Misleading error message (INI - the header is empty)

When a header contains Cyrillic letters, it says the header is empty:

use strict;
use warnings;
use utf8;
# my $hdr = 'test';
my $hdr = 'тест';
open my $h, "<", \$hdr or die $!;
$ perl a.pl
Strings with code points over 0xFF may not be mapped into in-memory file handles
Invalid argument at a.pl line 6.

open my $h, "<", $hr or croak ($self->SetDiag (1010));

I'm running perl-5.36.0.

Man page: also mention how to read from a a string

Currently the Text::CSV man page only mentions how to get input from files.

However, other man pages show more ways,

         $dom = XML::LibXML->load_xml(
             location => $file_or_url
             # parser options ...
           );
         $dom = XML::LibXML->load_xml(
             string => $xml_string
             # parser options ...
           );
         $dom = XML::LibXML->load_xml(
             string => (\$xml_string)
             # parser options ...
           );
         $dom = XML::LibXML->load_xml({
             IO => $perl_file_handle
             # parser options ...
           );
         $dom = $parser->load_xml(...);

Therefore it would be great if the Text::CSV man page mentioned ways to read from a string, etc. which may be needed if preprocessing is necessary, e.g., to strip comments for #54.
Or say "Text::CSV cannot read from a string, as we need to seek() ..."

Text::CSV_PP BUG

please check the following code:

perl -e 'use Text::CSV_PP; my $c = Text::CSV_PP->new({allow_whitespace => 1}); $c->parse(q{"111","000"}); print join "\t", "parsed data:", $c->fields, "\nversion:", $c-version;'

the expected parsed data should be 2 fields: 111 and 000,
but the output is only one field: 111,00

Default value of decode_utf8 ?

Param description says that: "This attributes defaults to TRUE."

However later doc says

$csv = Text::CSV->new ();

is equivalent to

 $csv = Text::CSV->new ({
    ...
    decode_utf8         => 0,

BTW: also "This attributes" should be changed to "This attribute".

Text::CSV_PP can't say a field when it contains new line.

Hi,

Text::CSV_PP can't say a field when it contains new line.

t.csv

no,name,data
1,tom,"PING
FAIL"
2,john,"PING\nFAIL"
$ perl -MText::CSV=csv -e '$c=Text::CSV->new; foreach (@{csv({ in=>"t.csv", headers => "auto" })  }) { $_->{data} =~ /PING/ && $c->say(STDOUT,[@$_{qw/name data/}]) }'
tom,"PING
FAIL"
john,PING\nFAIL

Text::CSV(aka. Text::CSV_XS) works as expected.



$ perl -MText::CSV_PP=csv -e '$c=Text::CSV_PP->new; foreach (@{csv({ in=>"t.csv", headers => "auto" })  }) { $_->{data} =~ /PING/ && $c->say(STDOUT,[@$_{qw/name data/}]) }'
john,PING\nFAIL

where's tom row??


$ perl -MText::CSV_PP=csv -e '$c=Text::CSV_PP->new; foreach (@{csv({ in=>"t.csv", headers => "auto" })  }) { $_->{data} =~ /PING/ && $c->say(STDOUT,[@$_{qw/name/}]) }'
tom
john

works as expected. 
It seems that Text::CSV_PP can't say(print) a field when it contains new line properly.
but no problem with Text::CSV_XS.

Edited:
Text::CSV_PP also works well with binary mode.
https://metacpan.org/pod/Text::CSV#Embedded-newlines

$ perl -MText::CSV=csv -e '$c=Text::CSV->new; $c->binary(1); foreach (@{csv({ in=>"test.csv", headers => "auto" })  }) { $_->{data} =~ /PING/ && $c->say(STDOUT,[@$_{qw/name data/}]) }'
tom,"PING
FAIL"
john,PING\nFAIL

Why Text::CSV_XS and Text::CSV_PP are different ?

Offer option to not put empty columns into hashes created

Idea: offer an option to not put empty columns into hashes created.

use Text::CSV qw( csv );
my $aoh = csv( in => "data.csv", headers => "auto" );

is great, but if I want a smaller hash, I must then do:

for my $row (@$aoh) {
    for my $column ( keys %$row ) {
        delete $row->{$column} unless length $row->{$column};
    }
}

Therefore please perhaps also offer:

my $aoh = csv( in => "data.csv", headers => "auto", skip_empty_columns => 1 );

so people can get a smaller hash from the start.

What's the big deal?

Could reduce the size of the hash by e.g., 99% in certain cases.

Well just do that delete stuff yourself like you said.

But the big bloated hash has has already been created...
we still haven't reduced at least initial memory usage.

Version: 2.00-1

Text::CSV man page should mention something about comments

Emacs has

csv-comment-start is a variable defined in ‘csv-mode.el’.
Its value is "#"

  Automatically becomes buffer-local when set.

Documentation:
String that starts a comment line, or nil if no comment syntax.
Such comment lines are ignored by CSV mode commands.
This variable is buffer local; its default value is that of
‘csv-comment-start-default’.  It is set by the function
‘csv-set-comment-start’ -- do not set it directly!

Therefore the Text::CSV man page should mention something about comments.
E.g., "Not allowed!"

Leading Zero problem with \r\n

Hello,
I try to import CSV files with values like “001”. This works as long as I use \n as linefeed. With a windows linefeed \r\n it does not work (results in “1”).
I tried several things to solve this problem, but nothing seems to work. Maybe I miss something obvious?

Here is a quick excerpt from my code (to see what settings I am using):

    # Create CSV Object
    # http://perlmaven.com/how-to-read-a-csv-file-using-perl
    my $csv = Text::CSV->new ({
        binary      => 1,
        auto_diag => 1,
        sep_char    => $myCSVSeparator,
    });

    # Open CSV File
    print "Opening file \"$file\" for overview.\n" if DEBUG1;
    open(my $data, '<:encoding(utf8)', $file) or die "Could not open '$file' $!\n";

    # Get header data
    my @headerData = $csv->column_names ($csv->getline ($data));
    my $colCount = @headerData;

    # Get table data
    my $tableDataHashRef = $csv->getline_hr_all ($data);
    my $rowCount = scalar(@$tableDataHashRef);

some csv function "Alternative invocations" examples do not work

In the Alternative invocations section of the csv function documentation, the second and third examples do not work:

my $csv = Text::CSV->new ();
my $aoa = $csv->csv (in => "file.csv");

my $csv = Text::CSV->new ({ sep_char => ";" });
my $aoh = $csv->csv (in => "file.csv", bom => 1);

When each of these is run, you get the error:

Odd number of elements in hash assignment at /opt/ActivePerl-5.18/site/lib/Text/CSV_XS.pm line 1120.

This is because the Text::CSV object is passed as the first argument, and it does not pass the check at the beginning of Text::CSV_XS::_csv_attr:
my %attr = (@_ == 1 && ref $_[0] eq "HASH" ? %{$_[0]} : @_) or croak;

which causes @_ to be returned as an odd number of elements.

Versions: Text-CSV_XS-1.41, Text-CSV-2.00

Wanted: a convenient shorthand for when the first line of a CSV contains column names

I do a lot of converting spreadsheets to CSV, schlepping them to a server, then going through them. I find myself writing code like this all the time:

open(my $fh, '<', ...);
my $csv = Text::CSV->new;
$csv->column_names(@{ $csv->getline($fh) });
while (my $data = $csv->getline_hr($fh)) {
    ...
}    

It's line three that particularly bothers me. Why do I have to type this all the time? (Although passing $fh around all the time is annoying as well.)

I'd really like to be able to say something like e.g.

my $csv = Text::CSV->new_from_file(...);
while (my $data = $csv->data) {
    ...
}

(It occurs to me, as I write this, that a module called e.g. Text::CSV::FromFile could implement this functionality very simply and elegantly, and I might end up writing something like that when I get a few tuits.)

Error during parsing field that contains comma and escaped quote (')

Hi,

here is the example:

my $csv = Text::CSV->new ({ escape_char => "\\", allow_loose_escapes => 1, auto_diag=>1 });
$csv->parse (q("error, a\' string"));

Returns:

# CSV_PP ERROR: 2027 - EIQ - Quoted field not terminated

This fields is parsed as expected if remove either comma or escape character.

bind_columns changes input to after_parse callback

Binding columns effectively hides the input data from the after_parse callback. For example,

#! perl

use v5.10;
use strict;
use warnings;

use Text::CSV;

my $data = <<EOF;
col1,col2,col3
val1,val2,val3
EOF

use Data::Dumper;

my $csv = Text::CSV->new( { callbacks => {after_parse => sub {say Dumper $_[1]; }} } );
my $fh;

open $fh, '<', \$data;
1 while $csv->getline( $fh );

my @row = (undef) x 3;
$csv->bind_columns( \( @row ) );

open $fh, '<', \$data;
1 while $csv->getline( $fh );

Results in:

$VAR1 = [
          'col1',
          'col2',
          'col3'
        ];

$VAR1 = [
          'val1',
          'val2',
          'val3'
        ];

$VAR1 = [];

$VAR1 = [];

I don't think there's any way around this without copying the data (as the parsed data are no longer stored in an array that's controlled by Text::CSV) which defeats the purpose of bind_columns.

I haven't looked into how this affects all of the callbacks; at least for after_parse there's a workaround:

after_parse => sub {
    my @refs = $_[0]->bind_columns;
    if ( defined $refs[0] ) {
        say Dumper ${$_} for @refs;
    }
    else {
        say Dumper $_[1];
    }
}

The documentation doesn't mention this side effect. While it's somewhat obvious after you're bitten by it, it'd be useful if the documentation indicated where it comes into play.

Thanks!

UTF-8 flag on string breaks empty_is_undef

Everything works fine here:

$ perl -MText::CSV -MEncode -e 'my $csv = Text::CSV->new({"empty_is_undef" => 1}); my $line = "foo,,bar,"; $csv->parse($line); use Data::Dumper; print Dumper $csv->fields;'
$VAR1 = 'foo';
$VAR2 = undef;
$VAR3 = 'bar';
$VAR4 = undef;

But the same string with UTF-8 flag enabled results in empty string instead of undefs, despite empty_is_undef being set.

$ perl -MText::CSV -MEncode -e 'my $csv = Text::CSV->new({"empty_is_undef" => 1}); my $line = "foo,,bar,"; Encode::_utf8_on($line); $csv->parse($line); use Data::Dumper; print Dumper $csv->fields;'
$VAR1 = 'foo';
$VAR2 = '';
$VAR3 = 'bar';
$VAR4 = '';

Perl 5.20.2, Text::CSV 1.33

'csv' function missing from SYNOPSIS

The csv function is a lot easier to use than the OO interface, and helps produce smaller, neater code. Text::CSV_XS has it in the SYNOPSIS section of the module's POD. Couldn't you also include it there? I didn't know of the function's existence or usefulness for many years because of its absence from the SYNOPSIS, where I would easily have seen how much easier things become when using it. I know people who have written their own wrapper functions to make Text::CSV easier to use, because they didn't know of the csv function! It would help everyone I think, if the csv function were included in the SYNOPSIS.

Thanks.

module() (and is_xs()/is_pp()) don't work

With Text:CSV(1.95) and Text::CSV_XS(1.34) installed via cpan (tests pass) using perl v5.24.1, the following program complains about the use of an unintialized value.

use strict;
use warnings;

use Text::CSV;

my $csv = Text::CSV->new();

print $csv->module(), "\n";
$ perl foo.pl
Use of uninitialized value in print at foo.pl line 8.

$

The module sub relies on an _MODULE attribute, which neither Text::CSV_PP nor Text::CSV_XS seem to set.

I noticed this while trying to convince myself that I was, in fact, using the XS implementation.

FR: Reading multiple CSVs from a single file

Occasionally I have to process files that contain multiple CSVs. Each of these CSVs is stored in the file as a heading, followed by the data lines, followed by an empty line (or eof).

It would be nice if Text::CSV had an option that basically says: stop reading after an empty line. This would make it possible to write something similar to:

csv (in => $fh,  out => \@aoh1, stop_at_empty => 1);
csv (in => $fh,  out => \@aoh2, stop_at_empty => 1);
csv (in => $fh,  out => \@aoh3, stop_at_empty => 1);

CR in CSV gives me an error

Hello,
according to the doc the module accepts "\n", "\r" and "\r\n".

I have a minimal CSV with this content (displayed by od):

od -c test.csv 
0000000   b   l   a   ;  \r  \n
0000006

Every approach to parse this file ended in an error message.

This code

  my $csv = Text::CSV
[test.csv.gz](https://github.com/makamaka/Text-CSV/files/3345969/test.csv.gz)

->new({ sep_char => ';' ,  auto_diag => 1  }); 
  $csv->diag_verbose (2);
 
 
  open(my $data, '<', $datevFile) or die "Could not open '$datevFile' $!\n";
  while (my $line = <$data>) {
    chomp $line;
   
    if ($csv->parse($line)) {
   
        my @fields = $csv->fields();

        print("field0 " . $fields[0] . "\n");
        print("field1 " . $fields[1] . "\n");
        #print("field2 " . $fields[2] . "\n");
   
    } else {
        warn "Line could not be parsed: $line\n";
    }   
  }

gives me this error

ERROR: 2037 - EIF - Binary character in unquoted field, binary off @ rec 0 pos 5

Mention missing final step in getting header order back

We read

       keep_headers

       When using hashes,  keep the column names into the arrayref passed,  so
       all headers are available after the call in the original order.

       my $aoh = csv( in => "file.csv", keep_headers => \my @hdr );

OK, but then you need to mention how to get them back:

       csv( in => $aoh, headers => \@hdr, out => "out.csv" );

else they'll go down the drain!

Test::CSV_PP treats eof() differently than CSV_XS

Text::CSV_PP appears to call eof() as a function, rather than a method.
This is probably incorrect behavior, as the test case below only fails for _PP, not _XS.

#!/usr/bin/env perl
use strict;
use warnings;
use Test::More;

use Text::CSV_PP;
use Text::CSV_XS;

BEGIN {
    package FakeFileHandle;

    sub new { return bless { line => "foo,bar,baz\n" }, shift }

    sub getline {
        my $self = shift;
        return delete $self->{line};
    }

    sub eof {
        my $self = shift;
        return not exists $self->{line};
    }
};

PP: {
    my $pp = Text::CSV_PP->new({binary => 1});
    my $fh = FakeFileHandle->new;
    ok(!$fh->eof);
    eval {
        is_deeply( $pp->getline($fh), [qw[ foo bar baz ]]);
    };
    is($@, '', "no exception thrown");
    ok($fh->eof);
}

XS: {
    my $pp = Text::CSV_XS->new({binary => 1});
    my $fh = FakeFileHandle->new;
    ok(!$fh->eof);
    eval {
        is_deeply( $pp->getline($fh), [qw[ foo bar baz ]]);
    };
    is($@, '', "no exception thrown");
    ok($fh->eof);
}


done_testing;

Mention auto_diag => 1 is incompatible with strict => 1

On the man page at

       strict

        my $csv = Text::CSV->new ({ strict => 1 });
                $csv->strict (0);
        my $f = $csv->strict;

       If this attribute is set to 1, any row that parses to a different number of fields than the previous row will cause the parser to
       throw error 2014.

warn that adding it to the example.

my $csv = Text::CSV->new( { binary => 1, auto_diag => 1, strict => 1 } );

will cause

CSV_PP ERROR: 2014 - ENF - Inconsistent number of fields @ rec 236 pos 1

at the end of all files, as the parser attempts to get a line beyond the end of the file.
libtext-csv-perl:
Installed: 1.99-1

is_missing() working properly?

I notice there are no tests for the is_missing() function, so I created a few, but it looks like is_missing returns undef when it shouldn't. Am I misunderstanding the is_missing or getline_hr functions?

The test is also my fork of this repo in case Markdown eats the code..

!/usr/bin/perl

use strict;
$^W = 1;

use Test::More tests => 9;

BEGIN {
$ENV{PERL_TEXT_CSV} = 0;
use_ok "Text::CSV", ();
plan skip_all => "Cannot load Text::CSV" if $@;
}

open FH, ">_99test.csv";
print FH <<EOC;

2
EOC
close FH;

ok (my $csv = Text::CSV->new (), "new");
is ($csv->is_missing(0), undef, "is_missing()");

open FH, "<_99test.csv";
ok ($csv->column_names ('code'));
ok (my $hr = $csv->getline_hr (_FH));
is ($csv->is_missing(0), undef, "is_missing()");
ok ($hr = $csv->getline_hr (_FH));
is (int $hr->{code}, 2, "code==2");
isnt ($csv->is_missing(0), undef, "isn't is_missing()");
close FH;

when reading line by line, skip_empty_rows('skip') does not skip a trailing empty row right before EOF

Given an input file like:

a,b,c,d
1,2,0,4

5,7,9,3

When skip_empty_rows is set to skip, and Text::CSV is reading line by line, the first empty line is skipped, but the second empty line is returned as an empty row rather than undef (EOF).

I will open a PR for this, including tests that illustrate the situation more precisely.

This same bug is present in Text::CSV_XS; I will open a separate bug and PR for that project.

Thanks,
Corey

Small inconsistency or, at least, ambigious.

I have a question on SO and people advice to use your module.

Module's synopsis has:

my $aoa = csv (in => "data.csv"   );    # as array of array
my $aoh = csv (in => "data.csv",  headers => "auto");   # as array of hash
 
# Write array of arrays as csv file
csv (in => $aoa, out => "file.csv", sep_char=> ";");

If I do not provide out the result and call is made in scalar context the $aoa or $aoh will be returned.
if I provide out the result will be saved there.

So call result and out is two different things. First is the data how it was read from csv file into memory, and out is our csv formatted data.

Why when I do $data = csv( in => $aoa, out => 'file.csv', headers => 'auto' ) I get in my $data csv formatted data instead of $aoh? nowhere in the doc I did not find that $data should return csv formatted array.

Q: Is there an option to turn off escape char if whole string is not quoted?

Hi. I have bank statements from different banks. One send correct CSV, but other not:

"АТ ""ОТП БАНК""";nextvalue

АТ КБ "ПРИВАТБАНК";nextvalue

I doubt that they will change something. So I ask about an option which will allow to not count " char at second line as escape char if cell value is not quoted.

->eof with Text::CSV_PP vs Text::CSV_XS

Using this code:

#!/usr/bin/env perl                     

use strict;                             
use warnings;                           
use Text::CSV;                          
use IO::All -utf8;                      

my $csv = Text::CSV->new({binary => 1});
$csv->eol("\n");                        

my $io = io 'foo.csv';                  
$csv->getline_all($io, 0, 10);          

All is well when IO::All, Text::CSV and Text::CSV_XS is installed. However, if not installing Text::CSV_XS and thereby using Text::CSV_PP, the same code fails with the following message:

Can't call method "eof" on an undefined value at IO/All/Base.pm line 128.

I have checked that Text::CSV_PP is indeed there by running perl -e 'use Text::CSV_PP;'.

Versions (all from CPAN):

  • Perl : 5.24.0
  • Text::CSV : 1.33
  • IO::All : 0.86

BOM without a header line.

The option detect_bom is only available in the header method, but not all CSVs have header lines. The detect_bom functionality should be used on the first line of the file, not just the header line.

Usage example in error message incomplete. Just warn about undef instead.

$ cat e
use Text::CSV qw( csv );
my $aoa;
csv (in => $aoa, out => "file.csv");
$ perl -w e
usage: my $aoa = csv (in => $file); at e line 3.

Here according to the usage message, it looks like "in" can only be used
with files. But in fact it can be used with much more.

The problem is an undef $aoa. So it should in fact warn about that instead.

Encoding Issue: Arabic Characters Conflict with Another Language in the Same Row

I've noticed an issue with my script that queries a database and generates a CSV file. Specifically, when a row contains characters from languages other than Arabic and English, the Arabic characters in that row aren't encoded correctly. It seems that either the combine or string methods of CSV are causing this problem.

For example, in a line where the name "Pelé" is present, the Arabic word "نسيج" is transformed into random characters like "Ù�سÙ�ج,Ù�سÙ�ج". Interestingly, when I open the file in VI, I observe that the same word appears differently encoded in two different locations.

I've experimented with both the binary => 1 option and without it, but the issue persists.

my $csv = Text::CSV->new( { binary => 1 } );
open my $fh, ">:encoding(UTF-8)", "new.csv" or die "new.csv: $!";
print $fh "\x{feff}";

my $status = $csv->combine(@row);    # combine columns into a string
my $line   = $csv->string();
print $fh $line

When i take Text::CSV out of hte equation, and just write directly to the fine with minimum transformation (commas and quotes), it works fine.

The issue is also present in CSV_XS

Double headers when both detect_bom and headers are provided

Hi!

Using the module for a command-line tool, I'm consistently setting headers => 'auto' and give the possibility to specify a detect_bom based on a command-line option.

Tests show that when both options are active, headers are read twice, which ends up skipping the first line (where real headers live) and trying to set headers from the second line.

I'd say that this behaviour is surprising and sub-optimal, although admittedly there's no indication that this should not behave this way in the docs. I'm currently working this around like this:

my $has_bom = ...;
my @csv_args = (
   ($has_bom ? (detect_bom => 1) : (headers => 'auto')),
    ...
);

If you're interested, this is a full test for this:

#!/usr/bin/env perl
use strict;
use warnings;

use Test::More;
use Encode qw< decode encode >;
use Text::CSV_PP 'csv';
use Data::Dumper;

ok 1, 'tests start';

my $input = input();
my $input2 = input2();

subtest 'plain array' => sub {
   open my $fh, '<', \$input or die "open(): $!";
   my $parsed = csv(in => $fh, sep_char => ',');
   isa_ok $parsed, 'ARRAY';

   my $n_read = @$parsed;
   is $n_read, 3, 'lines read';
   is length($parsed->[0][0]), 4, 'length of first parsed thing';
};

subtest 'with headers => auto' => sub {
   open my $fh, '<', \$input or die "open(): $!";
   my $parsed = csv(in => $fh, sep_char => ',', headers => 'auto');
   isa_ok $parsed, 'ARRAY';

   my $n_read = @$parsed;
   is $n_read, 2, 'records read';

   my $record = $parsed->[0];
   isa_ok $record, 'HASH';
   my $key;
   for my $k (keys %{$record}) {
      next if $record->{$k};
      $key = $k;
      last;
   }
   is length($key), 4, 'length of "first" key';
};

subtest 'with detect_bom => 1' => sub {
   open my $fh, '<', \$input or die "open(): $!";
   my $parsed = csv(in => $fh, sep_char => ',', detect_bom => 1);
   isa_ok $parsed, 'ARRAY';

   my $n_read = @$parsed;
   is $n_read, 2, 'records read';

   my $record = $parsed->[0];
   isa_ok $record, 'HASH';
   my $key;
   for my $k (keys %{$record}) {
      next if $record->{$k};
      $key = $k;
      last;
   }
   is length($key), 3, 'length of "first" key (stripped!)';
};

subtest 'input with detect_bom => 1 and headers => auto' => sub {
   open my $fh, '<', \$input or die "open(): $!";

   my $parsed = eval {
      csv(in => $fh, sep_char => ',', detect_bom => 1, headers => 'auto');
   };
   if ($parsed) {
      isa_ok $parsed, 'ARRAY';

      my $n_read = @$parsed;
      is $n_read, 2, 'records read';

      my $record = $parsed->[0];
      isa_ok $record, 'HASH';
      my $key;
      for my $k (keys %{$record}) {
         next if $record->{$k};
         $key = $k;
         last;
      }
      is length($key), 3, 'length of "first" key (stripped!)';
   }
   else {
      fail "could not parse: $@";
   }
};

subtest 'input2 with detect_bom => 1 and headers => auto' => sub {
   open my $fh, '<', \$input2 or die "open(): $!";

   my $parsed = eval {
      csv(in => $fh, sep_char => ',', detect_bom => 1, headers => 'auto');
   };
   if ($parsed) {
      isa_ok $parsed, 'ARRAY';
      my $n_read = @$parsed;
      is $n_read, 2, 'records read' or diag "read $n_read";

      my $record = $parsed->[0];
      isa_ok $record, 'HASH';
      my $key;
      for my $k (keys %{$record}) {
         next if $record->{$k};
         $key = $k;
         last;
      }
      is length($key), 3, 'length of "first" key (stripped!)'
         or diag "key<$key>";
   }
   else {
      fail "could not parse: $@";
   }
};

done_testing();

sub input {
   my $string = <<"END";
\x{FEFF}foo,bar
,12
0,11
END
   return encode('UTF-8', $string);
}

sub input2 {
   my $string = <<"END";
\x{FEFF}foo,bar
NOMNOM,da-bah
0,11
END
   return encode('UTF-8', $string);
}

Output:

$ perl -MText::CSV_PP -E 'say $Text::CSV_PP::VERSION'
2.02

$ prove -v ./csv_pp-test01.t 
./csv_pp-test01.t .. 
ok 1 - tests start
# Subtest: plain array
    ok 1 - A reference of type 'ARRAY' isa 'ARRAY'
    ok 2 - lines read
    ok 3 - length of first parsed thing
    1..3
ok 2 - plain array
# Subtest: with headers => auto
    ok 1 - A reference of type 'ARRAY' isa 'ARRAY'
    ok 2 - records read
    ok 3 - A reference of type 'HASH' isa 'HASH'
    ok 4 - length of "first" key
    1..4
ok 3 - with headers => auto
# Subtest: with detect_bom => 1
    ok 1 - A reference of type 'ARRAY' isa 'ARRAY'
    ok 2 - records read
    ok 3 - A reference of type 'HASH' isa 'HASH'
    ok 4 - length of "first" key (stripped!)
    1..4
ok 4 - with detect_bom => 1
# Subtest: input with detect_bom => 1 and headers => auto
# CSV_PP ERROR: 1012 - INI - the header contains an empty field @ rec 2 pos 0
    not ok 1 - could not parse: INI - the header contains an empty field
    1..1
not ok 5 - input with detect_bom => 1 and headers => auto
# Subtest: input2 with detect_bom => 1 and headers => auto

    #   Failed test 'could not parse: INI - the header contains an empty field'
    #   at ./csv_pp-test01.t line 86.
    # Looks like you failed 1 test of 1.

#   Failed test 'input with detect_bom => 1 and headers => auto'
#   at ./csv_pp-test01.t line 88.
    ok 1 - A reference of type 'ARRAY' isa 'ARRAY'
    not ok 2 - records read

    #   Failed test 'records read'
    #   at ./csv_pp-test01.t line 99.
    #          got: '1'
    #     expected: '2'
    ok 3 - A reference of type 'HASH' isa 'HASH'
    not ok 4 - length of "first" key (stripped!)
    1..4
not ok 6 - input2 with detect_bom => 1 and headers => auto
1..6
    # read 1

    #   Failed test 'length of "first" key (stripped!)'
    #   at ./csv_pp-test01.t line 109.
    #          got: '6'
    #     expected: '3'
    # key<NOMNOM>
    # Looks like you failed 2 tests of 4.

#   Failed test 'input2 with detect_bom => 1 and headers => auto'
#   at ./csv_pp-test01.t line 115.
# Looks like you failed 2 tests of 6.
Dubious, test returned 2 (wstat 512, 0x200)
Failed 2/6 subtests 

Test Summary Report
-------------------
./csv_pp-test01.t (Wstat: 512 Tests: 6 Failed: 2)
  Failed tests:  5-6
  Non-zero exit status: 2
Files=1, Tests=6,  0 wallclock secs ( 0.00 usr  0.01 sys +  0.05 cusr  0.00 csys =  0.06 CPU)
Result: FAIL

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.