我正在使用Linux。
我有一个以下格式的文件
; Header info
;--+-----+--+----+-+----------------
;Co TASK# ID PROP X Remarks
;de (full desc.)
;--+-----+--+----+-+----------------
AAA P00_1 000Lean - not yet done
AAB P00_2 11 Fat X 20190606
AAC P00_3 1 MidleX canceled
并希望将其转换为这种格式的 csv 文件
Code;Task#;ID;PROP;X;Remarks
AAA;P00_1;000;Lean;-;not yet done
AAB;P00_2;11;Fat;X;20190606
AAC;P00_3;1;Midle;X;canceled
字段的长度各不相同,但最大长度可达相应“+”的列 -> 例如,请参见以“AAC”开头的行和“Middle”字段。
第一步是确定标题格式描述中“+”号的列,并插入“;”通过尊重“超大”字段(如“中间”)(见上文),在每行的这些列上。
在 Linux 下如何使用 awk 或 sed 或 ... 来实现此目的?
干杯!
答案1
如果您有固定的架构(我已为其分配了名称input-schema.csv
)
column,start,length
Code,0,4
Task,4,6
ID,10,3
PROP,13,5
X,18,2
Remarks,20,17
您可以使用csvkit并运行(使用您的输入文件,我已指定为 name input.csv
)
<input.csv grep -v '^;' | in2csv -f fixed -s input-schema.csv | csvformat -D ";"
具有
Code;Task;ID;PROP;X;Remarks
AAA;P00_1;000;Lean;-;not yet done
AAB;P00_2;11;Fat;X;20190606
AAC;P00_3;1;Midle;X;canceled
答案2
对于 GNU awk,使用FIELDWIDTHS
for处理固定宽度数据。从表格轮廓中获取字段宽度。并删除每个字段的尾随空格。
BEGIN { FS = "+"; OFS = ";" }
NR == 2 {
for (i=1;i<=NF;i++) f = (f ? f " " : "") length($i)+1
FIELDWIDTHS = f
print "Code;Task#;ID;PROP;X;Remarks"
}
!/^;/ {
for (i=1;i<=NF;i++) sub(/[[:space:]]+$/,"",$i)
print
}
用法:
$ awk -f tst.awk file
Code;Task#;ID;PROP;X;Remarks
AAA;P00_1;000;Lean;-;not yet done
AAB;P00_2;11;Fat;X;20190606
AAC;P00_3;1;Midle;X;canceled
答案3
awk '
NR == 2 {
for (i = 1; i <= length(); i++) {
if (substr($0, i, 1) == "+" || i == length()) {
fieldWidths[++fieldNr] = i - prevFieldEndPos
prevFieldEndPos = i
}
}
}
NR > 5 {
fieldNr = 0
for (i = 1; i <= length(); i += fieldWidths[fieldNr]) {
fieldVal = substr($0, i, fieldWidths[++fieldNr])
gsub(/^[[:blank:]]*|[[:blank:]]*$/, "", fieldVal)
printf "%s", (i > 1 ? ";" : "") fieldVal
}
print ""
}' infile
输出(不处理标头部分,因为不清楚它是如何填充的):
AAA;P00_1;000;Lean;-;not yet done
AAB;P00_2;11;Fat;X;20190606
AAC;P00_3;1;Midle;X;canceled