Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force Text::CSV to store number as text?

I am writing some perl code to create a .csv file from records in the database, using the Text::CSV module. Occasionally, one or more of the fields in my table will contain multiple repeating 0s, which will write to the CSV as a single 0. I'm trying to find out how to force the number as text format, so that all of the 0s from those fields will remain in tact.

    use Text::CSV_XS;

    sub write_file {
       my ($self, %params) = @_;

       my $fh = $params{fh};

       .. do stuff
       .. get database rows

       my $csv = Text::CSV_XS->new({ sep_char => ',' });
    
       for my $row (@$rows) {
           my @fields = (
              $row->{name},
              $row->{address},
              $row->{code}
           );

           $csv->combine(@fields);

           print $fh $csv->string . "\r\n"
               or die 'Write error.';
       }

With this approach, everything looks good most of the time. But, when code comes through as "00000", it is truncated and written as "0" in my CSV.

I've investigated $csv->types, but this only allows the type to be defined when decoding during a parse.

I've also tried wrapping the fields in quotes using $csv->quote(@fields), with no luck.

like image 824
ComputersAreNeat Avatar asked Mar 17 '21 04:03

ComputersAreNeat


People also ask

How do I keep my numbers formatted in CSV?

To preserve all the digits in text-formatted numbers, you have to import the downloaded CSV file as raw data into a new Excel spreadsheet, set the column datatypes as needed, and then save the new file as an Excel workbook. Excel (XLSX) files will preserve these formats, CSV files won't.


2 Answers

Refer to always_quote() to force the the combined fields to be quoted

use Text::CSV_XS;
my $csv = Text::CSV_XS->new( { sep_char => ',' } );

my @fields = ( "0", "00", "000" );

$csv->combine(@fields);
print $csv->string . "\n";

$csv->always_quote(1);
$csv->combine(@fields);
print $csv->string . "\n";

which results in

0,00,000
"0","00","000"
like image 104
David Dyck Avatar answered Oct 22 '22 10:10

David Dyck


Normalize your data

If the problem is that

  • You want leading 0s,
  • The leading zeros in your input are NOT significant (ie, scientific notation)

Then you can simply normalize the data with sprintf

$x = 5;
print sprintf("%05d", $x)

You can choose how many leading zeros you want in your output, and make all colums read the same.

like image 1
NO WAR WITH RUSSIA Avatar answered Oct 22 '22 09:10

NO WAR WITH RUSSIA