【问题标题】:How to remove leading character from a specific column in a pipe delimited file?如何从管道分隔文件的特定列中删除前导字符?
【发布时间】:2018-12-30 11:51:56
【问题描述】:

我有一个像这样的管道分隔文本文件

TEST|F123433|F123433|TEST
TEST|F123434|F123434|TEST
TEST|F123435|F123435|TEST
TEST|F123436|F123436|TEST
TEST|F123437|F123437|TEST

我正在尝试从第 2 列和第 3 列中删除前导“F”。这是预期的输出。

TEST|123433|123433|TEST
TEST|123434|123434|TEST
TEST|123435|123435|TEST
TEST|123436|123436|TEST
TEST|123437|123437|TEST

我尝试使用下面的 sed 来执行此操作,但它仅从第 2 列而不是第 3 列中删除了“F”

sed 's/^TEST|F/TEST|/g'

【问题讨论】:

  • 想出一个更具代表性的例子,可以测试一个潜在的解决方案,看看它是否有效。 sed 's/F//g' 会根据您发布的输入生成您发布的输出,因此它可能不是一个好的测试用例,因为根据您的要求,它不能用于区分工作和非工作解决方案。
  • 您只需要使用反斜杠转义|。它是正则表达式中的特殊字符。
  • @miken32 实际上在(旧版)sed 中是相反的;反斜杠会将管道变成元字符。

标签: regex awk sed


【解决方案1】:

使用sed(这仅适用于上述示例),您可以将|F 全局替换为|

$ sed -E 's/\|F/\|/g' file

您可以限制|F 的前两个实例(不一定是列号),并用sed 进行两个非全局替换:

sed -e 's/\|F/\|/' -e 's/\|F/\|/' file

或者,以 ERE 形式:

$ sed -E 's/^([^|]*)\|F/\1|/; s/([^|]*)\|F/\1|/' file

awk 提供了更好、更灵活的逐字段解决方案,允许您指定哪一列:

$ awk  'BEGIN{FS=OFS="|"} {for (i=2; i<=3;i++)sub(/^F/,"",$i);}1' file
TEST|123433|123433|TEST
TEST|123434|123434|TEST
TEST|123435|123435|TEST
TEST|123436|123436|TEST
TEST|123437|123437|TEST

【讨论】:

    【解决方案2】:

    你也可以试试简单的awk。将sub 函数用于第二和第三字段。

    awk 'BEGIN{FS=OFS="|"} {sub(/^F/,"",$2);sub(/^F/,"",$3)} 1'  Input_file
    TEST|123433|123433|TEST
    TEST|123434|123434|TEST
    TEST|123435|123435|TEST
    TEST|123436|123436|TEST
    TEST|123437|123437|TEST
    

    【讨论】:

      【解决方案3】:

      您需要使用捕获组复制F 之后第二列中的所有内容。

      sed 's/^TEST|F\([^|]*\)|F/TEST|\1|/'
      

      没有必要使用 g 修饰符,因为您每行只进行一次替换(并且以 ^$ 锚定的模式无论如何只能匹配一次)。

      【讨论】:

      • 我忘记了最后的/
      【解决方案4】:

      使用sed,使用捕获组:

      sed -E -n 's/^(TEST\|)F(.*)F(.*)/\1\2\3/p'
      

      输出:

      TEST|123433|123433|TEST
      TEST|123434|123434|TEST
      TEST|123435|123435|TEST
      TEST|123436|123436|TEST
      TEST|123437|123437|TEST
      

      【讨论】:

        【解决方案5】:

        这可能对你有用(GNU sed):

        sed -r 's/(F|([^F|]?))([^|]*)/\2\3/2;s/(F|([^F|]?))([^|]*)/\2\3/3' file
        

        这将删除由| 分隔的列的第一个字符F 用于第二列和第三列。它使用了一个不匹配的反向引用为空的事实,因此在替换的 RHS 中使用这样的引用将有效地删除先前的匹配。

        【讨论】:

          【解决方案6】:
          awk '{gsub(/\|F/,"|")}1' file
          
          TEST|123433|123433|TEST
          TEST|123434|123434|TEST
          TEST|123435|123435|TEST
          TEST|123436|123436|TEST
          TEST|123437|123437|TEST
          

          【讨论】:

            【解决方案7】:

            使用 Perl

            $ cat > bala.txt
            TEST|F123433|F123433|TEST
            TEST|F123434|F123434|TEST
            TEST|F123435|F123435|TEST
            TEST|F123436|F123436|TEST
            TEST|F123437|F123437|TEST
            
            $ perl -F"[|]" -lane ' s/^.// for @F[1..2] ; print join("|",@F) ' bala.txt
            TEST|123433|123433|TEST
            TEST|123434|123434|TEST
            TEST|123435|123435|TEST
            TEST|123436|123436|TEST
            TEST|123437|123437|TEST
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2018-03-17
              • 2016-07-06
              • 2018-10-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-04-02
              相关资源
              最近更新 更多