我有一些csv文件被破坏,因为在某些字段中存在诸如控制字符,输入和分隔符之类的垃圾。没有控制字符的示例模型数据:
id;col 1;col 2;col 3
1;data 11;good 21;data 31
2;data 12;cut
in two;data 32
3;data 13;good 23;data 33
4;data 14;has;extra delimiter;data 34
5;data 15;good 25;data 35
6;data 16;cut
and;extra delimiter;data 36
7;data 17;data 27;data 37
8;data 18;cut
in
three;data 38
9;data 19;data 29;data 39
我用awk处理上面的垃圾:
BEGIN { FS=OFS=";" } # delimiters
NR==1 { nf=NF; } # header record is fine, use the NF
NR>1 {
if(NF<nf) { # if NF less that header's NF
prev=$0 # store $0
if(getline==1) { # read the "next" line
succ=$0 # set the "next" line to succ
$0=prev succ # rebuild a current record
}
}
if(NF!=nf) # if NF is still not adequate
$0=succ # expect original line to be malformed
if(NF!=nf) # if the "next" line was malformed as well
next # well skip "next" line and move to next
} 1
当然,上面的程序将失败记录4
和6
(因为实际数据有几个字段,其中额外的分隔符可能潜伏)和8
(因为我只阅读下一行,如果NF
太短了。我可以忍受失去4
和6
,但8
可能会失败吗?
此外,if
循环连续三次for
的尖叫声,但是星期五下午在这里,我的日子已接近$
,我无法旋转我的脑袋了。你们有没有脑力储备我可以借用吗?我没有想到的任何最佳实践?
答案 0 :(得分:2)
她的关键是保留一个包含仍未“完整”的行的缓冲区;一旦它们打印出来并清除缓冲区:
awk -F';' 'NF>=4 && !nf {print; next} # normal lines are printed
{ # otherwise,
if (nf>0) { # continue with a "broken" line by...
buff=buff OFS $0 # appending to the buffer
nf+=NF-1 # and adding NF
} else { # new "broken" line, so...
buff=$0 # start buffer
nf=NF # set number of fields already seen
}
}
nf>=4{ # once line is complete
print buff # print it
buff=""; nf=0 # and remove variables
}' file
在这里,buff
是这样的缓冲区,nf
是一个内部计数器,用于跟踪当前记录中已经看到的字段数(就像您在尝试时所做的那样)。
我们在追加到缓冲区时(即从损坏的流的第二行)添加NF-1
,因为NF==1
的行不添加任何记录但只是与最后一个字段连接上一行:
8;data 18;cut # NF==3 |
in # NF==1 but it just continues $3 | all together, NF==4
three;data 38 # NF==2 but $1 continues $3 |
使用您的示例输入:
$ awk -F';' 'NF>=4 && !nf {print; next} {buff=(nf>0 ? buff OFS : "") $0; nf+=(nf>0 ? NF-1 : NF)} nf>=4{print buff; buff=""; nf=0}' a
id;col 1;col 2;col 3
1;data 11;good 21;data 31
2;data 12;cut in two;data 32
3;data 13;good 23;data 33
4;data 14;has;extra delimiter;data 34
5;data 15;good 25;data 35
6;data 16;cut and;extra delimiter;data 36
7;data 17;data 27;data 37
8;data 18;cut in three;data 38
9;data 19;data 29;data 39