您好我有一个csv文件,看起来像这样。请注意,并非所有数据都是多行的!
225253;abc;def;ghi;"- sometext
- sometext
- 3sometext
";asd,asd;58.2500;False;False;False;17;0.0000;;
我的目标是使用bash脚本将其转换为以下形式:
225253;abc;def;ghi;"- sometext - sometext - 3sometext";asd,asd;58.2500;False;False;False;17;0.0000;;
我的第一个猜测就是这个。但不知怎的,它不会起作用......
sed -e 's/\"\([^"]+\)\"//g'
答案 0 :(得分:1)
执行此操作的干净方法是使用Text::CSV,注释中建议的@JonathanLeffler或类似的内容。也就是说,使用专用于处理CSV文件的库。请参阅底部的Perl实现。
但是,默认情况下通常不会安装Text::CSV
,因此您可能必须自己安装它。如果这不是一个选项或者对你来说太难,那么一个不太完美但更简单的awk
解决方案可能已经足够好了,基于similar question:
awk -F ";" -v nf=13 'NF < nf { line = line (line ? OFS : "") $0; fields += NF } fields >= nf { print line; line=""; fields=0 } NF == nf'
供参考,使用Text::CSV
:
use Text::CSV;
my $sep = ';';
my $csv = Text::CSV->new({ binary => 1, sep_char => $sep });
while (my $row = $csv->getline(*STDIN)) {
print join($sep, map { s/\n$//; s/ *\n/ /g; $_ } @$row), "\n";
}
将其保存在文件transform-csv.pl
中并使用以下命令运行:
perl transform-csv.pl < sample.csv
答案 1 :(得分:1)
这可能适合你(GNU sed):
sed -r ':a;/^[^"]*("[^"]*")+(;[^"]+|$)/b;$!{N;s/\n//;ba}' file
这会查找具有匹配引号的行。如果它找到一条带有不匹配引号的行,则会附加下一行,删除换行符并重复,直到引号匹配或到达文件末尾。
N.B。这不符合引号内的报价。
答案 2 :(得分:0)
perl -MText::CSV_XS -e'my $csv = Text::CSV_XS->new({binary=>1,sep_char=>";"});while(my $row = $csv->getline(ARGV)){$csv->print(STDOUT,[map s/\n/ /g,@$row])}'
或者您也可以使用Text::CSV
。将参数添加到解析器构造函数以调整其他行为。
答案 3 :(得分:0)
awk '{gsub(/\n/,"")}1' FS=";" RS=";" ORS=";" file
给出
225253;abc;def;ghi;"- sometext - sometext- sometext";asd,asd;58.2500;False;False;False;17;0.0000;;
<强>更新强>
或在Gnu Awk第4版中使用patsplit
:
BEGIN { FS=RS=";"}
{
if (patsplit($0,a,/"[^"]+"/,s)) {
gsub(/\n/,"",a[1])
printf "%s%s%s", s[0],a[1],s[1]
}
else
printf "%s", $0
printf ";"
}
这只会删除双引号内的换行符。
答案 4 :(得分:0)
也可以试试这个sed脚本。它匹配在行结束前具有开放双引号"
而没有字段分隔符;
的行。假设只有当它们出现在双引号字段中时才需要删除换行符。它还假设引用整个字段(至少结束像"stuff";
)。如果情况并非如此,则应进行微调。
:again
/"[^;]*$/ {
N
s/\n//
b again
}
s/"[^;]*";/;/g
将其放入script.sed
并按sed -r -f script.sed file
如果保留引用字段,则只需从脚本中删除最后一行。