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

Hi Monks!

Please comment on this quick-n-dirty implementation of a csv join function:

sub csv_join { join ",", map { s{"}{""}g || m{[ ,]} ? qq{"$_"} : $_ } (my @x = @_); }

Comments on correctness and efficiency / golf score are welcome. It can assumed that the arguments will not contain any control characters (newlines, for instance.) It also tries to not use quotes when they are not needed.

And, yes, I know about Text::CSV, but I can't use that module in my project (right now).

Replies are listed 'Best First'.
Re: a q-n-d csv_join function
by GrandFather (Saint) on Mar 02, 2009 at 01:04 UTC

    Yes, even you can use CPAN.

    'golf score' is not something to be concerned with if you are aiming for production code. Correctness and maintainability on the other hand should be of concern.


    True laziness is hard work
Re: a q-n-d csv_join function
by ikegami (Patriarch) on Mar 02, 2009 at 02:52 UTC

    How about the following. Quick, clean, compatible to your future migration to Text::CSV_XS, and it came from PerlMonks instead of CPAN, so it must be ok!

    package Text::CSV_PP; ###################################################################### +########## # # Text::CSV_PP - Text::CSV_XS compatible pure-Perl module # ###################################################################### +########## require 5.005; use strict; use vars qw($VERSION); use Carp (); $VERSION = '1.18';
    =head1 AUTHOR Makamaka Hannyaharamitu, E<lt>makamaka[at]cpan.orgE<gt> Text::CSV_XS was written by E<lt>joe[at]ispsoft.deE<gt> and maintained by E<lt>h.m.brand[at]xs4all.nlE<gt>. Text::CSV was written by E<lt>alan[at]mfgrtl.comE<gt>. =head1 COPYRIGHT AND LICENSE Copyright 2005-2008 by Makamaka Hannyaharamitu, E<lt>makamaka[at]cpan. +orgE<gt> This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L<Text::CSV_XS>, L<Text::CSV> I got many regexp bases from L<http://www.din.or.jp/~ohzaki/perl.htm> =cut
Re: a q-n-d csv_join function
by ELISHEVA (Prior) on Mar 02, 2009 at 01:05 UTC
    Elegant. Some minor points:
    • need to consider other types of whitespace, so [ ,] => [\s,]
    • passing a reference to an array is more efficient than passing the array - if you pass the array you will have to pass by reference each array member rather than just the single array reference. To preserve the calling syntax of csv_join(@someArray) use the prototype \@.

      However, you can only use \@ if your parameters are arrays. If hardcoded lists are used as parameters, e.g. csv_join('a','b','c') instead of arrays, e.g. csv_join(@aFields), then you will need to use the version that passes the entire array. The \@ prototype would complain about extra parameters and failed attempts to take references of constant items.

    • interpolating quotes unnecessary for ","
    • my @x is unnecessary - map copies on its own
    • golf score (which shouldn't matter, but if you care) - use /.../ not m{...} and s{...}{...}

    With revisions (using the \@ protoype)p>

    sub csv_join(\@) { join ',', map {s/"/""/g || /[\s,]/ ? qq{"$_"} : $_} (my @x=@{$_[0]}); }

    With revisions (passing the entire array):

    sub csv_join { join ',', map { s/"/""/g || /[\s,]/ ? qq{"$_"} : $_} (my @x=@_); }

    Best, beth

    Update: Re-added my @x. Thanks, jwkrahn. I had overlooked the effect of s/// on the elements of @_.

    Update 2: Added an alternative if the function needs to be called with hard coded lists, e.g. csv_join('a','b','c')

      my @x is unnecessary - map copies on its own

      map in the example modifies $_ and @_ is an alias to the original array so you need the copy in order not to modify the original array passed to the subroutine.

      Re: my @x...

      if you do not pass the arguments as an array-ref, then something like my @x is necessary. Without the my @x =, perl will complain with:

      Modification of a read-only value attempted at ....

      unless these is another way around this problem...

        Hmmm... my test code (without my @x) didn't trigger that warning, but then I was passing arrays and not hard-coded lists of data. I think you would get that problem if you were calling csv_join('a', 'b', 'c') for example.

        Hard coded lists would also be a problem with the \@ prototype since it needs to take a reference to the array that was passed to csv_join('a','b','c') and hard coded lists don't have references. In fact, you would get something like this if the prototype is \@ and you called csv_join('a', 'b', 'c')

        Type of arg 1 to main::csv_join must be array (not constant item) at M +onks/QuickCsvJoin.pm line 33, near "'c') " Too many arguments for main::csv_join at Monks/QuickCsvJoin.pm line 33 +, near "'c') "

        If you need to make calls like csv_join('a','b','c') rather than csv_join(@aFields), then you will have to pass the array rather than just a reference to it. I've updated the original reply with the alternative. See above.

        Best, beth

      Update: Re-added my @x. Thanks, jwkrahn. I had overlooked the effect of s/// on the elements of @_.

      which just goes to amplify my earlier comment concerning 'correctness and maintainability' ;-).


      True laziness is hard work