【问题标题】:Fixing broken csv files using awk使用 awk 修复损坏的 csv 文件
【发布时间】:2016-10-07 13:44:51
【问题描述】:

我有一些损坏的 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

上面的程序自然会失败记录46(因为实际数据有几个字段可能隐藏额外的分隔符)和8(因为如果NF太短,我只会阅读下一行. 我可以忍受失去468 可能可行吗?

另外,三个连续的ifs 尖叫着要一个​​for 循环,但现在是星期五下午,我的日子快到了$,我无法再绕着它转头了。你们还有我可以借用的大脑储备吗?有什么我没有想到的最佳做法?

【问题讨论】:

  • 期望的输出是什么?

标签: csv awk


【解决方案1】:

她的关键是保留一个缓冲区,其中包含仍未“完整”的行;一旦它们出现,打印它们并清除缓冲区:

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

【讨论】:

    猜你喜欢
    • 2020-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-09
    • 2020-02-01
    相关资源
    最近更新 更多