File Coverage

blib/lib/Text/CSV/Easy_PP.pm
Criterion Covered Total %
statement 36 38 94.7
branch 10 20 50.0
condition 3 9 33.3
subroutine 7 7 100.0
pod 2 2 100.0
total 58 76 76.3


line stmt bran cond sub pod time code
1             package Text::CSV::Easy_PP;
2 3     3   41074 use 5.010;
  3         11  
  3         115  
3 3     3   25 use strict;
  3         6  
  3         95  
4 3     3   16 use warnings FATAL => 'all';
  3         5  
  3         110  
5              
6 3     3   28 use Carp;
  3         5  
  3         219  
7 3     3   16 use Exporter qw(import);
  3         6  
  3         1868  
8              
9             our @EXPORT_OK = qw(csv_build csv_parse);
10              
11             =head1 NAME
12              
13             Text::CSV::Easy_PP - Easy CSV parsing and building implemented in PurePerl
14              
15             =head1 SYNOPSIS
16              
17             use Text::CSV::Easy_PP qw(csv_build csv_parse);
18              
19             my @fields = csv_parse($string);
20             my $string = csv_build(@fields);
21              
22             =head1 DESCRIPTION
23              
24             Text::CSV::Easy_PP is a simple module for parsing and building CSV lines. This module is written in PurePerl. For a faster alternative, see L. Either way, you should just be able to use L directly and it will determine which version to use.
25              
26             This module conforms to RFC 4180 (L) for both parsing and building of CSV lines.
27              
28             =over 4
29              
30             =item 1. Use commas to separate fields. Spaces will be considered part of the field.
31              
32             abc,def, ghi => ( 'abc', 'def', ' ghi' )
33              
34             =item 2. You may enclose fields in quotes.
35              
36             "abc","def" => ( 'abc', 'def' )
37              
38             =item 3. If your field contains a line break, a comma, or a quote, you need to enclose it in quotes. A quote should be escaped with another quote.
39              
40             "a,b","a\nb","a""b" => ( 'a,b', "a\nb", 'a"b' )
41              
42             =item 4. A trailing newline is acceptable (both LF and CRLF).
43              
44             abc,def\n => ( 'abc', 'def' )
45             abc,def\r\n => ( 'abc', 'def' )
46              
47             =back
48              
49             When building a string using csv_build, all non-numeric strings will always be enclosed in quotes.
50              
51             =head1 SUBROUTINES
52              
53             =head2 csv_build( List @fields ) : Str
54              
55             Takes a list of fields and will generate a CSV string. This subroutine will raise an exception if any errors occur.
56              
57             =cut
58              
59             sub csv_build {
60 1     1 1 5 my @fields = @_;
61             return join ',', map {
62 1 50       22 if ( !defined )
  2 50       14  
63             {
64 0         0 '';
65             }
66             elsif (/^\d+$/) {
67 0         0 $_;
68             }
69             else {
70 2         5 ( my $str = $_ ) =~ s/"/""/g;
71 2         13 qq{"$str"};
72             }
73             } @fields;
74             }
75              
76             =head2 csv_parse( Str $string ) : List[Str]
77              
78             Parses a CSV string. Returns a list of fields it found. This subroutine will raise an exception if a string could not be properly parsed.
79              
80             =cut
81              
82             sub csv_parse {
83 1     1 1 3 my ($str) = @_;
84              
85 1 50       4 return () unless $str;
86              
87 1         3 my $last_pos = 0;
88              
89 1         1 my @fields;
90 1         12 while (
91             $str =~ / (?:^|,)
92             (?: "" # don't want a capture group here
93             | "(.*?)(?
94             | ([^",\r\n]*) # try to match an unquoted field
95             )
96             (?:\r?\n(?=$)|) # allow a trailing newline only
97             (?=,|$) /xsg
98             )
99             {
100 2   33     8 my $field = $1 || $2;
101              
102             # is the field a numeric 0.
103 2 50 33     12 if ( defined($field) && $field =~ /^0+$/ ) {
104              
105             # don't do anything.
106             }
107             else {
108              
109             # if we don't have a value, we have either an undef or an empty string.
110             # "" will be an empty string, otherwise it should be undef.
111 2 0 33     8 $field ||= ( $& =~ /^,?""(?:\r?\n)?$/ ? "" : undef );
112             }
113              
114             # track the pos($str) to ensure each field happends immediately after the
115             # previous match. also, account for a leading comma when $last_pos != 0
116 2 100       10 croak("invalid line: $str")
    50          
117             if pos($str) > $last_pos + length($&) + ( $last_pos != 0 ? 1 : 0 );
118              
119 2         3 $last_pos = pos($str);
120              
121 2 50       13 if ($field) {
122 2 50       6 croak("quote is not properly escaped")
123             if ( $field =~ /(?
124              
125             # unescape the quotes.
126 2         3 $field =~ s/""/"/g;
127             }
128 2         10 push @fields, $field;
129             }
130              
131 1 50       3 croak("invalid line: $str") if $last_pos != length($str);
132              
133 1         14 return @fields;
134             }
135              
136             1;
137              
138             =head1 SEE ALSO
139              
140             =over 4
141              
142             =item L
143              
144             =item L
145              
146             =item L
147              
148             =back
149              
150             =head1 AUTHOR
151              
152             Thomas Peters, Eweters@me.comE
153              
154             =head1 COPYRIGHT AND LICENSE
155              
156             Copyright (C) 2013 by Thomas Peters
157              
158             This library is free software; you can redistribute it and/or modify
159             it under the same terms as Perl itself, either Perl version 5.12.4 or,
160             at your option, any later version of Perl 5 you may have available.
161              
162             =cut