我有一个CSV文件,转换为.DAT。我有一个AWK文件,它假设要进行DAT文件的映射。 AWK文件中的代码如下所示。
DAT文件的内容如下所示(制表符分隔):
ODT AGE CDT CO SEX TIME VALUE COMMENT
P3 Y6-8 ACT FG F 2011 1297
P4 Y3-4 EMP FG M 2011 6940 b
P1 Y7-9 GRT FG F 2011 0 c
我需要做的是:
这是我的代码,只修复了第一点
BEGIN {
FS = "," ;
OFS = " " ;
}
{
if(NR == 1)
{
split($0, tmp, ",");
for(i = 1; i <= NF; i++)
fields[tmp[i]] = i
print tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8]
else
{
split($0, tmp, ",");
for(i = 1; i <= NF; i++)
fields[tmp[i]] = i
print tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8]
}
}
dat文件中的预期结果:
ODT AGE CDT CO SEX TIME NUMB STRING_COM STRING_STATUS
P3 Y6-8 ACT FG F 2011 1297
P4 Y3-4 ERT FG M 2011 6940 b
P1 Y7-9 GRT FG F 2011 0 c
在CSV文件中,分隔符为&#34;,&#34;但是dat文件必须带有制表符分隔符,这就是为什么我有代码.... FS =&#34;,&#34; 关于第三点,解释是: 我可能会收到其他不需要的列。 总而言之,我已经以某种方式指定只需要这些列:ODT AGE CDT CO SEX TIME VALUE COMMENT) 收到的任何其他列都必须被忽略
CSV文件为:
ODT,AGE,CDT,CO,SEX,TIME,VALUE,COMMENT
P3,Y6-8,ACT,FG,F,2011,1297,
P4,Y3-3,EMP,FG,M,2011,6940,b
P1,Y7-9,GRT,FG,F,2011,0,c
下面提供的解决方案工作正常。 还有一些问题:
如果我在AGE或CDT之后将列COMMENT放在&#34; c&#34;字符在第二行添加。第二行包含两个选项卡,然后是&#34; c&#34;字符。 如果COMMENT在最后并包含字符&#34; c&#34;,&#34; bcc&#34;结果仅在STRING_STATUS上进行,而不是进行分离&gt; &#34; C&#34;转到STRING_COM和&#34; bcc&#34;转到STRING_STATUS
必须实施以下案例:
是否有人可以帮助解决这个问题?
答案 0 :(得分:0)
如果所有行都具有相同的列顺序:
awk '
BEGIN {
FS=","; OFS="\t";
a["ODT"]=1;a["AGE"]=1;a["CDT"]=1;a["CO"]=1;
a["SEX"]=1;a["TIME"]=1;a["VALUE"]=1;a["COMMENT"]=1;
}
NR==1 {
$NF=substr($NF,1,length($NF)-1);
for(i=1;i<=NF;i++) if($i in a) a[$i]=i;
}
{ print $a["ODT"],$a["AGE"],$a["CDT"],$a["CO"],$a["SEX"],$a["TIME"],NR==1?"NUMB":$a["VALUE"],
NR==1?"STRING_COM"OFS"STRING_STATUS":($a["COMMENT"]!="c"?""OFS$a["COMMENT"]:$a["COMMENT"]);
}' input.txt
我稍微更改了输入,添加了一列(ADDED
)并重新排序了另外两列(TIME
和VALUE
):
ODT,ADDED,AGE,CDT,CO,SEX,VALUE,TIME,COMMENT
P3,111,Y6-8,ACT,FG,F,1297,2011,
P4,222,Y3-3,EMP,FG,M,6940,2011,b
P1,333,Y7-9,GRT,FG,F,0,2011,c
输出:
ODT AGE CDT CO SEX TIME NUMB STRING_COM STRING_STATUS
P3 Y6-8 ACT FG F 2011 1297
P4 Y3-3 EMP FG M 2011 6940 b
P1 Y7-9 GRT FG F 2011 0 c
修改强>
如果输入的列多于所需的列,则额外的列不会出现在输出中,例如我在此处使用的输入有一个额外的列ADDED
,它不会出现在输出中。
它将按照所讨论的首选顺序打印输出,即ODT AGE CDT CO SEX TIME NUMB STRING_COM STRING_STATUS
,无论它们在输入中出现的顺序如何。再次在输入中,我使用VALUE
之前出现的列TIME
,但在输出TIME
中是第一列而NUMB
是第二列。通过
如果所有行都具有相同的列顺序
我的意思是如果所有行都遵循标题行的顺序。如果标题中的顺序为ODT AGE CDT CO SEX TIME VALUE COMMENT
,则如果标题中的顺序为AGE ODT CDT CO SEX TIME VALUE COMMENT
,则所有行中的数据将按此顺序显示,则所有其他行中的数据都具有此顺序。它并不假设例如ODT
始终是所有文件中的第一列,它假定在文件中订单由标题定义。如果不是这样,那么代码就不会起作用。
<强> EDIT2 强>
我测试过它:
ODT,ADDED,AGE,CDT,CO,SEX,VALUE,TIME,COMMENT
P3,111,Y6-8,ACT,FG,F,1297,2011,cd
P4,222,Y3-3,EMP,FG,M,6940,2011,bd
P1,333,Y7-9,GRT,FG,F,0,2011,c
作为输入文件,输出为:
ODT AGE CDT CO SEX TIME NUMB STRING_COM STRING_STATUS
P3 Y6-8 ACT FG F 2011 1297 cd
P4 Y3-3 EMP FG M 2011 6940 bd
P1 Y7-9 GRT FG F 2011 0 c
视觉bd
和cd
位于STRING_COM
列下,原因是标题长度超过标签大小,通常为8个字符。输出是制表符分隔的,可以打印两个选项卡以使它们显示在STRING_STATUS
下,但如果输出打算由另一个程序使用,则可能会导致一些问题,因为它会产生一个空字段。如果您只需要打印,可以将第12行更改为:
NR==1?"STRING_COM"OFS"STRING_STATUS":($a["COMMENT"]!="c"?""OFS""OFS$a["COMMENT"]:$a["COMMENT"]);
输出将是:
ODT AGE CDT CO SEX TIME NUMB STRING_COM STRING_STATUS
P3 Y6-8 ACT FG F 2011 1297 cd
P4 Y3-3 EMP FG M 2011 6940 bd
P1 Y7-9 GRT FG F 2011 0 c
答案 1 :(得分:0)
我用Ashkan的答案作为起点,并提出了下面的脚本。但是,这两点在CSV文件的上下文中没有意义,除非VALUE被引号(或其他东西)包围。请澄清。
- 如果VALUE为“14,38”而COMMENT为“d”,那么NUMB为“1438”且STRING(两者)为空
- 如果VALUE为“14,38”且COMMENT为“du”,则NUMB为“1438”且STRING_STATUS为“u”
醇>
Awk脚本:
BEGIN {
FS=","; OFS="\t";
a["ODT"]=1;a["AGE"]=1;a["CDT"]=1;a["CO"]=1;
a["SEX"]=1;a["TIME"]=1;a["VALUE"]=1;a["COMMENT"]=1;
}
NR==1 {
for (i=1;i<=NF;i++) {
if ($i in a) a[$i]=i;
}
print "ODT","AGE","CDT","CO","SEX","TIME","NUMB","STRING_COM","STRING_STATUS"
}
NR!=1{
split($0,line,/,/);
value = line[a["VALUE"]];
comment = line[a["COMMENT"]];
string_com="";
string_status="";
if (value==":") {
value="";
if (comment=="c") string_com = "c";
if (comment=="u") string_status = "u";
if (comment=="cd") string_com = "c";
if (comment=="bc") {
string_com = "c";
string_status = "b";
}
}
else {
if (comment=="c")
string_com = "c";
else if (comment=="d") {
# convert value
string_com = "";
string_status = "";
}
else if (comment=="du") {
# convert value
string_status = "";
}
else
string_status = comment;
}
print line[a["ODT"]],
line[a["AGE"]],
line[a["CDT"]],
line[a["CO"]],
line[a["SEX"]],
line[a["TIME"]],
value,
string_com,
string_status
}