File Coverage

blib/lib/AnyData/Format/CSV.pm
Criterion Covered Total %
statement 50 51 98.0
branch 10 14 71.4
condition 16 29 55.1
subroutine 7 7 100.0
pod 0 3 0.0
total 83 104 79.8


line stmt bran cond sub pod time code
1             #########################################################
2             package AnyData::Format::CSV;
3             #########################################################
4             # copyright (c) 2000, Jeff Zucker
5             #########################################################
6              
7             =head1 NAME
8              
9             AnyData::Format::CSV - tiedhash & DBI/SQL access to CSV data
10              
11             =head1 SYNOPSIS
12              
13             use AnyData;
14             my $table = adTable( 'CSV', $filename,'r',$flags );
15             while (my $row = each %$table) {
16             print $row->{name},"\n" if $row->{country} =~ /us|mx|ca/;
17             }
18             # ... other tied hash operations
19              
20             OR
21              
22             use DBI
23             my $dbh = DBI->connect('dbi:AnyData:');
24             $dbh->func('table1','CSV', $filename,$flags,'ad_catalog');
25             my $hits = $dbh->selectall_arrayref( qq{
26             SELECT name FROM table1 WHERE country = 'us'
27             });
28             # ... other DBI/SQL operations
29              
30             =head1 DESCRIPTION
31              
32             This is a plug-in format parser for the AnyData and DBD::AnyData modules. It will read column names from the first row of the file, or accept names passed by the user. In addition to column names, the user may set other options as follows:
33              
34             col_names : a comma separated list of column names
35             eol : the end of record mark, \n by default
36             quote_char : the character used to quote fields " by default
37             escape_char : the character used to escape the quote char, " by default
38              
39             If you are using this with DBD::AnyData, put ad_ in front of the flags, e.g.
40             ad_eol.
41              
42             Please refer to the documentation for AnyData.pm and DBD::AnyData.pm
43             for further details.
44              
45             =head1 AUTHOR & COPYRIGHT
46              
47             copyright 2000, Jeff Zucker
48             all rights reserved
49              
50              
51             =cut
52              
53              
54 3     3   13 use strict;
  3         5  
  3         122  
55 3     3   16 use warnings;
  3         3  
  3         93  
56 3     3   958 use AnyData::Format::Base;
  3         5  
  3         71  
57 3     3   13 use vars qw( @ISA $VERSION);
  3         4  
  3         1446  
58             @AnyData::Format::CSV::ISA = qw( AnyData::Format::Base );
59              
60             $VERSION = '0.12';
61              
62             sub new {
63 7     7 0 11 my $class = shift;
64 7   50     16 my $self = shift || {};
65 7   100     43 my $s = ${self}->{field_rsep} || ${self}->{field_sep} || q(,);
66 7         7 my $s1 = $s;
67             #$s1 =~ s/\\/\\\\/ if $s1 =~ /\+$/;
68             #$s1 =~ s/\+$//;
69             #die $s1;
70 7   100     24 ${self}->{field_sep} ||= q(,);
71 7   50     26 my $q = ${self}->{quote} ||= q(");
72 7   50     27 my $e = ${self}->{escape} ||= q(");
73 7   100     22 ${self}->{record_sep} ||= qq(\n);
74 7         264 $self->{regex} = [
75             qr/$q((?:(?:$e$q)|[^$q])*)$q$s?|([^$s1]+)$s?|$s/,
76             "$e$q",
77             $q
78             ];
79 7         33 return bless $self, $class;
80             }
81              
82             sub read_fields {
83 38     38 0 37 my $self = shift;
84 38   50     66 my $str = shift || return undef;
85 38         42 my @fields = ();
86 38         31 my $captured;
87 38   33     117 my $field_wsep = $self->{field_wsep} || $self->{field_sep};
88 38 50       70 if ($self->{trim}) {
89 0         0 $str =~ s/\s*($field_wsep)\s*/$1/g;
90             }
91 38         192 while ($str =~ m#$self->{regex}->[0]#g) {
92 96         129 $captured = $+;
93 96 100       232 $captured =~ s/$self->{regex}[1]/$self->{regex}[2]/g if $captured;
94 96 50 66     297 last if $captured && $captured eq "\n";
95 96         353 push(@fields,$captured);
96             };
97 38 100       81 push(@fields, undef) if substr($str,-1,1) eq $field_wsep;
98 38         131 return @fields;
99             }
100              
101             sub write_fields {
102 24     24 0 28 my $self = shift;
103 24         34 my @fields = @_;
104 24         24 my $str = '';
105 24   33     80 my $field_rsep = $self->{field_rsep} || $self->{field_sep};
106 24         27 $field_rsep = quotemeta($field_rsep);
107 24         25 my $field_wsep = $self->{field_sep};
108 24         39 $field_wsep =~ s/\\//g;
109             # if ($self->{ChopBlanks}) {
110             # $field_wsep =~ " $field_wsep ";
111             # }
112 24         36 for (@fields) {
113 72 50       111 $_ = '' if !defined $_;
114 72 100       119 if ($self->{field_sep} eq ',') {
115 36         32 s/"/""/g;
116 36 50 33     179 s/^(.*)$/"$1"/s if /,/ or /\n/s or /"/;
      33        
117             }
118 72         99 $str .= $_ . $field_wsep;
119             }
120 24         174 $str =~ s/$self->{field_sep}$/$self->{record_sep}/;
121 24         103 return $str;
122             }
123             1;
124              
125              
126