Little Code
Little Code

Reputation: 1545

Adding quotes to a CSV using perl

I've got a CSV that looks as follows:

A,01,ALPHA
00,D,CHARLIE
E,F,02

This is the desired file after transformation:

"A",01,"ALPHA"
00,"D","CHARLIE"
"E","F",02

As you can see, the fields that are entirely numeric are left unquoted, whilst the alpha (or alphanumeric ones) are quoted.

What would be a sensible way to go about this in Perl ?

Already commented below, but I've tried stuff like

perl -pe 's/(\w+)/"$1"/g'

And that doesn't work because \w obviously picks up the numerics.

Upvotes: 2

Views: 344

Answers (3)

zdim
zdim

Reputation: 66883

It seems that you are after a one-liner. Here is a basic one

perl -lpe '$_ = join ",", map /^\d+$/ ? $_ : "\"$_\"", split ",";' input.csv

Splits each line by , and passes obtained list to map. There each element is tested for digits-only /^\d+$/ and passed untouched, or padded with " otherwise. Then map's return is joined by ,.

The -l removes newline, what is needed since " pad the whole line. The result is assigned back to $_ in order to be able to use -p so that there is no need for explicit print.

The code is very easily used in a script, if you don't insist on an one-liner.

Processing of csv files is far better done by modules, for example Text::CSV

Upvotes: 2

Sundeep
Sundeep

Reputation: 23667

Another one-liner, input file modified to add a line with alphanumeric fields

$ cat ip.csv 
A,01,ALPHA
00,D,CHARLIE
E,F,02
23,AB12,53C

$ perl -F, -lane 's/.*[^0-9].*/"$&"/ foreach(@F); print join ",", @F' ip.csv 
"A",01,"ALPHA"
00,"D","CHARLIE"
"E","F",02
23,"AB12","53C"


To modify OP's attempt:

$ perl -pe 's/(^|,)\K\d+(?=,|$)(*SKIP)(*F)|\w+/"$&"/g' ip.csv 
"A",01,"ALPHA"
00,"D","CHARLIE"
"E","F",02
23,"AB12","53C"
  • (^|,)\K\d+(?=,|$)(*SKIP)(*F) this will skip the fields with digits alone and the alternate pattern \w+ will get replaced

Upvotes: 1

xxfelixxx
xxfelixxx

Reputation: 6602

I recommend not reinventing the wheel, but rather to use an already existing module, as zdim recommends. Here is your example using Text::CSV_XS

test.pl

#!/usr/bin/env perl

use warnings;
use strict;

use Text::CSV_XS;
use Scalar::Util qw( looks_like_number );

my $csv = Text::CSV_XS->new();
while (my $row = $csv->getline(*STDIN)) {
    my @quoted_row = map { looks_like_number($_) ? $_ : '"'. $_ .'"' } @$row;
    print join(',',@quoted_row) . "\n";
}

Output

cat input | perl test.pl
"A",01,"ALPHA"
00,"D","CHARLIE"
"E","F",02

Upvotes: 5

Related Questions