【问题标题】:Converting values in columns into rows将列中的值转换为行
【发布时间】:2016-11-09 08:30:17
【问题描述】:

我有一个文本文件,其中包含以下格式的数据。我想为第一列中的每个值创建一行。

0-09935152                          RC=3       CC=2   L=10-11
                   M=1
                   BNT=4
0-09935153                   F=31                     L=11
                   M=1
0-09935154                   F=31                     L=11
                   M=1
0-09935155                   F=31                     L=11
                   M=1
0-09935156                   F=31                     L=11
                   M=1
0-09935157                   F=31                     L=11
                   M=1
0-09935158                   F=31                     L=11
                   M=1
0-09935159                   F=31                     L=11
                   M=1
0-0993516                    F=31                     L=11
                   M=1
0-0993517                    F=31                     L=11
                   M=1
0-0993518                    F=31                     L=11
                   M=1
0-0993519                    F=0               CC=2
                   M=1

我想将所有对应的值拉到一行中。预期的输出将像

Code|M|F|CC|L|BNT|RC
0-09935152|1||2|10-11|4|3
0-09935153|1|31||11|||

我正在尝试使用 awk 来解析文本文件。我只能分离列,但无法继续进行。

感谢任何帮助。

【问题讨论】:

  • 所有相关数据都在同一行吗?这个例子看起来有点乱。
  • 不,这是挑战。对于我拥有的每个代码,例如第一行 0-09935152,相应的值在下一列中彼此下方。我正在尝试为每个制作一行。
  • 所有代码都是以“0-”开头的吗?
  • 不是必须的,它是一个数字,后跟“-”,然后是另一组数字。所以也有可能出现像 99-12345 这样的数字字符串

标签: unix text awk


【解决方案1】:

awk -f script.awk 文件

script.awk

BEGIN{RS="[ \n]";OFS="|";print "Code","M","F","CC","L","BNT","RC"} #print headers
length > 1 {size=split($0,t,"=")} #split values by "="
size==2{a[t[1]]=t[2]} #non-code values
size==1 && flag {print code,a["M"],a["F"],a["CC"],a["L"],a["BNT"],a["RC"];delete a;code=$0} #print values for each code switch
size==1 && !flag{flag++;code=$0} #skip first
{delete t;size=0} #clear data 
END{print code,a["M"],a["F"],a["CC"],a["L"],a["BNT"],a["RC"]} # print last value

输出

Code|M|F|CC|L|BNT|RC
0-09935152|1||2|10-11|4|3
0-09935153|1|31||11||
0-09935154|1|31||11||
0-09935155|1|31||11||
0-09935156|1|31||11||
0-09935157|1|31||11||
0-09935158|1|31||11||
0-09935159|1|31||11||
0-0993516|1|31||11||
0-0993517|1|31||11||
0-0993518|1|31||11||
0-0993519|1|0|2|||

【讨论】:

    【解决方案2】:
    BEGIN {
        RS="( +|\n)" # set the record separator to put every piece of data on a separate row for split
        OFS="|"      # # below: initialize the header
        arr[0]="Code"; arr["M"]="M"; arr["F"]="F"; arr["CC"]="CC"; arr["L"]="L"; arr["BNT"]="BNT"; arr["RC"]="RC"
    }
    /^[0-9]+-/ {     # print arr when new code starts
        print arr[0],arr["M"],arr["F"],arr["CC"],arr["L"],arr["BNT"],arr["RC"];
        delete arr;  # empty previous values from arr
        arr[0]=$0
    }
    {
        split($0,brr,"[=]"); # split from "=" to another array
        arr[brr[1]]=brr[2]   # first part is the index, latter is the value
    }
    END { # print the last line, too bad you can't "/^[0-9]+-/ || END {..."
    print arr[0],arr["M"],arr["F"],arr["CC"],arr["L"],arr["BNT"],arr["RC"];
    }
    
    $ awk -f test.awk test.in
    Code|M|F|CC|L|BNT|RC
    0-09935152|1||2|10-11|4|3
    0-09935153|1|31||11||
    0-09935154|1|31||11||
    [...]
    

    【讨论】:

    • 检查 OP 的 Commnets。代码可以以非零值开始
    • 伙计,这是我暑假第一天的初稿,请给我一分钟的早晨咖啡时间。 :D
    • 可以将 OFS 用于“|”分隔符
    • 是的,可能看起来更整洁。让我们看看。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-19
    • 2018-03-29
    • 1970-01-01
    相关资源
    最近更新 更多