均衡 csv 数据中的列数

Equalize number of columns in csv data

我正在从转换为 csv 的 PDF 文件中解析一些联系人数据,这导致根据缺失的条目每行的列数不同。

有没有一种方法可以使用 sed、awk、cut 等来纠正这个问题,方法是确保一些易于模式化的列匹配 - fx 确保电子邮件地址在可用时位于相同的列中,而其他列如 "Lifetime member" 或 "Guest" 当电子邮件不可用时?

第一列是 person/company 的名字,其余的是任意的。重点是提取联系信息(如电子邮件、phone 号码等)并将其放在相同的列中(如果可用)。 我的想法是检查电子邮件是否在第 6 列,如果不是,则在它之前添加一些空列等

示例数据:

Steve Smith;9828;1;+1234 567 2345;Guest;steve@example.org;1;1 12th st;48572 Nowhere
Steve Jobs;+1234 567 2345;noreply@example.org;1;48572 Nowhere
John Smith;9828;1;+1234 567 2345;Lifetime member;1;1 23rd st;48572 Nowhere
Peter Blavounius;2312;peter@blavounius.com

想要的输出:

Steve Smith;9828;1;+1234 567 2345;Guest;steve@example.org;1;1 12th st;48572 Nowhere
Steve Jobs;+1234 567 2345;;;;noreply@example.org;1;;48572 Nowhere
John Smith;9828;1;+1234 567 2345;Lifetime member;1;1 23rd st;48572 Nowhere
Peter Blavounius;2312;;;;peter@blavounius.com

这将帮助您入门,但并不完整,您仍然需要确定其他字段,到目前为止我所做的只是确定几个字段以向您展示方法:

$ cat tst.awk
BEGIN {
    FS=OFS=";"
    ARGV[ARGC] = ARGV[ARGC-1]
    ARGC++
}

{
    name = tel = email = digs4 = ""
    for (i=1;i<=NF;i++) {
        if (i == 1) {
            name=$i; $i=""; nameFld = 1
        }
        else if ($i ~ /^\+/) {
            tel=$i; $i=""; telFld = (i > telFld ? i : telFld)
        }
        else if ($i ~ /@/) {
            email=$i; $i=""; emailFld = (i > emailFld ? i : emailFld)
        }
        else if ($i ~ /^[0-9]{4}$/) {
            digs4=$i; $i=""; digs4Fld = (i > digs4Fld ? i : digs4Fld)
        }
    }
    maxFlds = (NF > maxFlds ? NF : maxFlds)
}

NR>FNR {
    for (i=1;i<=maxFlds;i++) {
        if (i == nameFld)       { $i = name }
        else if (i == telFld)   { $i = tel }
        else if (i == emailFld) { $i = email }
        else if (i == digs4Fld) { $i = digs4 }
        else { $i = $i } # make sure null fields are present
    }
    print
}

.

$ awk -f tst.awk file
Steve Smith;9828;1;+1234 567 2345;Guest;steve@example.org;1;1 12th st;48572 Nowhere
Steve Jobs;;;+1234 567 2345;48572 Nowhere;noreply@example.org;;;
John Smith;9828;1;+1234 567 2345;Lifetime member;;1 23rd st;48572 Nowhere;
Peter Blavounius;2312;;;;peter@blavounius.com;;;

它对您的输入文件执行 2 次传递 - 第一次确定与每个正则表达式匹配的最大字段编号,因为这是您希望匹配该正则表达式的每个字段出现在输出中的位置,第二次确定字段,清除它们在记录中的位置,然后将每个字段放在正确的位置。

您可以通过将字段的上下文与上面的正则表达式匹配或通过其在行中的固定位置(例如人名始终在字段 1 中)或通过它与其他内容的相对位置(例如出现在电子邮件地址之前或之后的单个数字或 before/after 第三个字段编号或....)

希望它有意义。添加一些 printfs 并尝试一下,如果您对此感到困惑,请提出问题。