【问题标题】:Remove unmatched values from a string in a pipe delimited file从管道分隔文件中的字符串中删除不匹配的值
【发布时间】:2018-10-21 20:19:45
【问题描述】:

我有一个输入文件,其列由| 分隔

输入文件:

COL1|COL2
CRIC1|IPL_M1;IPL_M2;TEST_M1
CRIC2|ODI_M1;IPL_M3
CRIC3|ODI_M3;TEST_M5
CRIC4|IPL_M5;ODI_M5;IPL_M;RANGI_M1
CRIC5|RANGI_M1

输出应仅在 COL2 中更改,其他列不应更改,即在 COL2 中应填充具有“IPL_”的字符串, 除了 'IPL_' 需要填充为 null 并删除不需要的分号。 COL2 可以包含尽可能多的值(IPL 和非 IPL 值)

预期输出:

COL1|COL2
CRIC1|IPL_M1;IPL_M2
CRIC2|IPL_M3
CRIC3|
CRIC4|IPL_M5;IPL_M6
CRIC5|

试过这个:

awk -F, -vOFS="|" '{$2=($2!="IPL_%")?" ":$2}1' File.txt

【问题讨论】:

  • 你有什么尝试吗?
  • 尝试了以下一个但它不起作用awk -F, -vOFS="|" '{$2=($2!="IPL_%")?" ":$2}1' File.txt
  • 在您的问题中加入您的尝试,并说明它以何种方式“不起作用”。

标签: unix awk


【解决方案1】:
$ awk '
    BEGIN { FS=OFS="|"; sfs=";" }
    NR>1 {
        n = split($2,f,sfs)
        $2 = ""
        for (i=1; i<=n; i++) {
            if (f[i] ~ /^IPL_/) {
                $2 = ($2=="" ? "" : $2 sfs) f[i]
            }
        }
    }
    { print }
' file
COL1|COL2
CRIC1|IPL_M1;IPL_M2
CRIC2|IPL_M3
CRIC3|
CRIC4|IPL_M5;IPL_M
CRIC5|

【讨论】:

    【解决方案2】:

    如果perl 没问题:

    $ perl -F'\|' -lane '$F[1] = join ";", grep {/IPL_/} split /;/,$F[1] if $.>1;
                         print join "|", @F' ip.txt
    COL1|COL2
    CRIC1|IPL_M1;IPL_M2
    CRIC2|IPL_M3
    CRIC3|
    CRIC4|IPL_M5;IPL_M
    CRIC5|
    
    • -F'\|' -lane 详见perldoc。这里,| 设置为输入字段分隔符,结果可从@F 数组中获得
    • if $.&gt;1 如果输入行号大于 1
      • split /;/,$F[1] 拆分; 上的第二个输入字段
      • grep {/IPL_/} 仅从拆分输出中过滤包含 IPL_ 的元素。如果需要,使用正则表达式锚
      • join ";" 使用; 加入grep 的输出,然后将结果保存回@F 数组的第二个元素
    • print join "|", @F 然后打印@F 数组的元素,以| 作为分隔符

    【讨论】:

      【解决方案3】:

      使用 sed

      sed -E '
        1b
        s/\|/\|;/
        s/IPL_M/@/g
        s/;[^@][^;]*//g
        s/\|;/\|/
        s/@/IPL_M/g
      ' infile
      

      【讨论】:

        【解决方案4】:

        由于所有很酷的 awk 答案都已经被采纳,我开始使用 PCRE 环视,所以,如果你可以使用 perl,这里有一个:

        perl -p -e 's/(?<=(\|)|(;))[^I][^P][^L][^;\n]*(;|(\n))|/\4/g if $.>1;s/;$//' file
        COL1|COL2
        CRIC1|IPL_M1;IPL_M2
        CRIC2|IPL_M3
        CRIC3|
        CRIC4|IPL_M5;IPL_M
        CRIC5|
        

        编辑:用少于 3 个字符串 (FO) 进行测试:

        $ cat foo
        COL1|COL2
        CRIC1|IPL_M1;IPL_M2;TEST_M1;FO;FO
        CRIC2|ODI_M1;IPL_M3;FO;FO
        CRIC3|FO;ODI_M3;TEST_M5
        CRIC4|FO;IPL_M5;FO;ODI_M5;IPL_M;RANGI_M1
        CRIC5|FO;RANGI_M1
        

        输出

        COL1|COL2
        CRIC1|IPL_M1;IPL_M2
        CRIC2|IPL_M3
        CRIC3|
        CRIC4|IPL_M           # fails if <3 preceeds a match 
        CRIC5|
        

        是的,它失败了。这似乎更好一些(更改为:[^I;\n][^P;\n]?[^L;\n]?):

        $ perl -p -e 's/(?<=(\|)|(;))[^I;\n][^P;\n]?[^L;\n]?[^;\n]*(;|(\n))|/\4/g 
          if $.>1;
          s/;$//' foo
        

        $ awk '
        BEGIN{ FS=OFS="|" } 
        {
            n=split($2,a,";")
            for(i=1;i<=n;i++)
                if(a[i]~/^IPL/||NR==1)
                    b=b (b==""?"":";") a[i]
            print $1,b;b=""
        }' file
        

        输出:

        COL1|COL2
        CRIC1|IPL_M1;IPL_M2
        CRIC2|IPL_M3
        CRIC3|
        CRIC4|IPL_M5;IPL_M
        CRIC5|
        

        【讨论】:

        • 稍后再发表评论,紧急情况在手。
        • 如果第二列的字符数少于 3 个怎么办? ;)
        • @Sundeep 失败了。
        • 您可以将其简化为perl -lpe 's/(?&lt;=[|;])[^I;][^P;]?[^L;]?[^;]*;?//g if $.&gt;1; s/;$//',但我仍然不认为这很强大.. 无论如何,欢迎来到 perl 世界:D
        【解决方案5】:

        Awk解决方案:

        awk 'BEGIN{ FS = OFS = "|" }
             NR == 1;
             NR > 1{
                 len = split($2, a, ";");
                 res = "";
                 for (i = 1; i <= len; i++)
                     if (a[i] ~ /^IPL_/) res = res (res != ""? ";" : "") a[i];
                 print $1, res
             }' file.txt
        

        输出:

        COL1|COL2
        CRIC1|IPL_M1;IPL_M2
        CRIC2|IPL_M3
        CRIC3|
        CRIC4|IPL_M5;IPL_M
        CRIC5|
        

        【讨论】:

          【解决方案6】:

          另一个awk 变体:

          awk -F '|' '
              NR == 1 { print; next }
              {
                  split($2, a, ";")
                  s = ""
                  for (i = 1; i <= length(a); ++i)
                      if (a[i] ~ /^IPL_/)
                          s = s a[i] ";"
                  print $1, substr(s, 1, length(s)-1)
              }' OFS='|' file
          

          生成

          COL1|COL2
          CRIC1|IPL_M1;IPL_M2
          CRIC2|IPL_M3
          CRIC3|
          CRIC4|IPL_M5;IPL_M
          CRIC5|
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-03-27
            • 2016-07-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多