首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CSV2 dat文件头和列操作

CSV2 dat文件头和列操作
EN

Stack Overflow用户
提问于 2014-04-22 14:03:46
回答 2查看 190关注 0票数 2

我有一个CSV文件,它被转换成.DAT,我有一个AWK文件,它假设要做DAT文件的映射。AWK文件中的代码如下所示。

DAT文件的内容如下(分隔的选项卡):

代码语言:javascript
复制
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

我要做的是:

  1. 保持标头与列的顺序一致
  2. 如果注释的值为"c“,则必须将列注释更改为STRING_COM,如果注释的值为"b”(或任何与“c”不同的内容),则注释列必须更改为STRING_STATUS。
  3. 无论收到什么其他列,除了这里提到的列,它们都必须被移除。
  4. 值列应在"NUMB“中重命名。

下面是我的代码,它只修复了第一点

代码语言:javascript
复制
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文件中的预期结果:

代码语言:javascript
复制
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文件中,分隔符是",“但是dat文件必须带有制表符分隔符,这就是为什么我有代码....FS=的原因,”关于第三点,解释是:我可能会收到其他不需要的列。因此,最后,我必须以某种方式指定只需要这些列: ODT、年龄、CDT、性别、时间、值、注释),其他任何收到的列都必须被忽略。

CSV文件是:

代码语言:javascript
复制
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之后,则在第二行中添加"c“字符。第二行包含两个制表符,然后是"c“字符。如果注释位于末尾,并包含字符"c",则"bcc“结果将仅在STRING_STATUS上显示,而不是执行分隔> "c”转到STRING_COM,而"bcc“则指向STRING_STATUS。

必须实施以下情况:

  1. 如果值为":“,则NUMB null。
  2. 如果值为":“并注释"c”,则NUMB null,STRING_COM为"c“。
  3. 如果值为":“并注释"u”,则NUMB null,STRING_STATUS为"u“。
  4. 如果值为"14,38“,而注释"d”,则NUMB为"1438“,字符串(两者均为空)为空。
  5. 如果值为"14,38“,而注释为"du”,则麻木为"1438“,STRING_STATUS为"u”。
  6. 如果值为":“并注释"cd”,则NUMB null,STRING_COM为"c“。
  7. 如果值为":“并注释"bc”,则NUMB null,STRING_COM为"c“,STRING_STATUS为"b”。

我该怎么做?

有人能在这个问题上提供帮助吗?

EN

回答 2

Stack Overflow用户

发布于 2014-04-22 19:15:53

如果所有行都有相同的列顺序:

代码语言:javascript
复制
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),并重新排序了另外两个列(TIMEVALUE):

代码语言:javascript
复制
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

输出:

代码语言:javascript
复制
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

我用以下方法进行了测试:

代码语言:javascript
复制
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

作为输入文件和输出是:

代码语言:javascript
复制
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

bdcdSTRING_COM列下,原因是标题比通常为8个字符的制表符长。输出是分开的,可以打印两个制表符以使它们在STRING_STATUS下出现,但如果输出要由另一个程序使用,则可能会导致一些问题,因为它会生成一个空字段。如果仅用于打印,则可以将行号12改为:

代码语言:javascript
复制
NR==1?"STRING_COM"OFS"STRING_STATUS":($a["COMMENT"]!="c"?""OFS""OFS$a["COMMENT"]:$a["COMMENT"]);

产出如下:

代码语言:javascript
复制
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
票数 0
EN

Stack Overflow用户

发布于 2014-05-29 00:26:42

我以Ashkan的答案作为起点,并给出了下面的脚本。但是,这两点在CSV文件的上下文中没有意义,除非值被引号(或其他东西)包围。请澄清。

  1. 如果值为"14,38“,而注释"d”,则NUMB为"1438“,字符串(两者均为空)为空。
  2. 如果值为"14,38“,而注释为"du”,则麻木为"1438“,STRING_STATUS为"u”。

Awk脚本:

代码语言:javascript
复制
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
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23221837

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档