如何用空格替换csv引用字段中的换行符?

时间:2018-06-07 19:38:48

标签: bash perl csv awk sed

在引用列中包含一些包含某些换行符的大型csv文件。我需要运行一个shell脚本,sed,awk,perl很好,只用空格替换引号内的换行符。必须保留行尾,并且我不知道列数或哪些字段可能包含这些嵌入的换行符。

对文件的进一步检查显示这是cat -v test_lf.csv

的结果
[ [1,5,5],[2,3,4] ]

在csv文件中哪个excel显示换行符??M - ^ @?是

我想使用tr来替换空间中的任何内容。我该怎么办?这个序列是什么?

我现在发现该文件的一小部分在字符和十六进制中看起来如下所示。

"NORTH ?M-^@?OLMSTED"
"PORT?M-^@?ST?M-^@?LUCIE"

我在Mac上,文件是utf-8,我的语言环境是utf-8。看起来字节是交换的(小端),因此十六进制3431 3136在字符表示中是1463。因此,从此输出中的字节60开始,我们有: 东西,S,T,空白,东西,东西,L和十六进制这是: 53a8 e254 a880 554c,53是S,54是T,4c是L.因此,在T和L之间有一个e2,a8,80序列。这会在Excel电子表格字段中生成换行符。
如何通过空格查找和替换这些字节?

3 个答案:

答案 0 :(得分:3)

我使用Perl模块Text::CSV

#!/usr/bin/perl

use strict;
use warnings;
use feature qw/say/;
use open IO => ':encoding(utf8)';
use open ':std';
use Text::CSV;

my $file = shift @ARGV;
open my $fh, "<", $file or die "cannot open $file: $!\n";

my $csv = Text::CSV->new({binary => 1});

while (my $row = $csv->getline($fh)) {
    my @no_newlines = map {s/\n/ /g; $_} @$row;
    $csv->combine(@no_newlines);
    say $csv->string();
}

close $fh;

然后你可以运行它:

/path/to/csvfixer.pl file.csv > fixed.csv

答案 1 :(得分:0)

经过大量读取csv文件的十六进制转储后,查看Mac上的数字和PC上的Excel处理嵌入式中断的方式的差异,似乎找到并更改中断编码的简单可移植方式不是值得努力。如果包含拆分的数据字段用引号括起来,那么Excel将读取它们,就像读取R中的read.csv一样。

答案 2 :(得分:-1)

假设引号字符是双引号"而转义字符也是双引号,如果在双引号数均为偶数时将所有换行符转换为空格,则可以使用sed执行此操作在模式空间。当数字是奇数时,你只需附加下一行。

sed ':a;/^\([^"]*"[^"]*"\)*[^"]*$/!{N;ba};y/\n/ /' file.csv

细节:

:a    # define the label "a"
/^\([^"]*"[^"]*"\)*[^"]*$/! # if not an even number of quotes
{
    N  # append the next line to the pattern space
    ba # go to label "a"
}
y/\n/ / # translate all line-feeds to spaces

如果报价未得到很好的平衡,则默认行为是不进行最后一次引用的部分。你可以改写它:

sed ':a;${y/\n/ /;s/$/"/};/^\([^"]*"[^"]*"\)*[^"]*$/!{N;ba};y/\n/ /' file.csv