使用sed从CSV中的引号中删除逗号为千位分隔符

时间:2014-05-10 20:25:00

标签: regex bash csv sed

sed非常不稳定,所以我不确定怎么排这样的

1,2,"12,345",x,y,"a,b"

并将其转换为

1,2,12345,x,y,"a,b"

所以数字" 12,345"变为12345,但" a,b"保持不变。

当值为数字时,我需要以某种方式保留逗号周围的值。我知道正则表达式如何只处理数字,但不确定如何删除逗号,而不是删除整个列。

5 个答案:

答案 0 :(得分:2)

解析CSV应该使用正确的csv解析器。我也会推荐perl

perl -MText::ParseWords -ne '
    @line = parse_line(",", 1, $_); 
    print join "," , map { s/,//g if $_ =~ /^[0-9,"]+$/; $_ } @line
' text.csv

测试:

$ cat text.csv
1,2,"12,345",x,y,"a,b"
"a,c","12,345",x,y,"a,b"

$ perl -MText::ParseWords -ne '
    @line = parse_line(",", 1, $_);
    print join "," , map { s/,//g if $_ =~ /^[0-9,"]+$/; $_ } @line
' text.csv
1,2,"12345",x,y,"a,b"
"a,c","12345",x,y,"a,b"

要进行就地更改,您可以使用-i选项或将输出重定向到另一个文件。

答案 1 :(得分:1)

Perl解决方案,使用Text::CSV

#!/usr/bin/perl
use warnings;
use strict;

use Text::CSV;

my @rows;

my $csv = 'Text::CSV'->new({ binary => 1}) or die 'Text::CVS'->error_diag;
open my $IN, '<', 'file.csv' or die $!;
while (my $row = $csv->getline($IN)) {
    for my $cell (@$row) {
        $cell =~ s/,// if $cell =~ /^[0-9,]+$/;
    }
    push @rows, $row;
}
$csv->eof or $csv->error_diag;

open my $OUT, '>', 'new.csv' or die $!;
$csv->print($OUT, $_) for @rows;
close $OUT or die $!;

答案 2 :(得分:1)

在一个正则表达式替换中,你可以做一些令人讨厌的事情: /\G(?|(")(\d+)(?:,(\d+))*(")|()([^,]+)()())(,|$)/g 用。。。来代替 \1\2\3\4\5

这应该可以与Perl一起使用。

演示:http://regex101.com/r/kQ5fU1

答案 3 :(得分:0)

您可以使用:

echo '1,2,"12,345",x,y,"a,b"' | sed 's/"\([0-9]*\),\([0-9]*\)"/\1\2/g'
编辑:实际上,只有在双引号之间插入一个逗号时,我的解决方案才有效。

答案 4 :(得分:0)

使用此模式(\d),(\d)(?!(([^"]*"){2})*[^"]*$)并替换w / $1$2
Demo