【问题标题】:Converting vim substitution with back references to sed, awk or similar unix command将带有反向引用的 vim 替换转换为 sed、awk 或类似的 unix 命令
【发布时间】:2014-11-21 03:21:28
【问题描述】:

嗨,我有一个命令,我一直在用它来处理 vim 中的文本文件;寻找一个字符串 R1 然后删除 3 行,2 行低于该字符串。 这在 vim 中运行良好,但是对于大文件来说非常慢:

:1,$s/\(r1.*\n\)\(\(.*\n\){2}\)\(\(.*\n\)\{3}\)/\1\2/g

例子:

R1                  30049              109769            109769 
                                       101598            281921 
                                 6.56608e+006      2.82861e+006 
                                 1.19658e+006      1.19658e+006 
                                      -515145           -515145 
                                      -223257            627520 
                                      -101598           -281921 
                                -6.56608e+006     -2.82861e+006 
                                       23.125            23.125 
                                        271.7            272.46 
                                          500               500 

会变成:

R1                  30049              109769            109769 
                                       101598            281921 
                                 6.56608e+006      2.82861e+006 
                                      -101598           -281921 
                                -6.56608e+006     -2.82861e+006 
                                       23.125            23.125 
                                        271.7            272.46 
                                          500               500 

此命令(或类似命令)能否更快地在 unix 终端中的 sed 或 awk 中运行?

非常感谢

【问题讨论】:

  • :g/R1/.+3,.+5d 中的vim 有什么问题(而不是恶魔般的正则表达式)?我相信这应该相当快。

标签: regex unix vim awk sed


【解决方案1】:

您可以在 Vim 中使用 :global 来解决这个问题,而不是使用多行正则表达式(这确实会很慢):

:global/^R1/.+3,.+5delete _

这会搜索所有以R1 开头的行,然后删除三到五行(进入黑洞寄存器_)。

【讨论】:

    【解决方案2】:

    使用 sed:

    sed -n '/^R1/{p;n;p;n;p;n;n;n;n};p;' file.txt
    

    使用备份编辑文件:

    sed -n -i.bak '/^R1/{p;n;p;n;p;n;n;n;n};p;' file.txt
    

    【讨论】:

      【解决方案3】:

      你可以通过 perl 做到这一点,

      $ perl -00pe 's/(\bR1.*\n(?:.*\n){2})(.*\n){3}/\1/g' file
      R1                  30049              109769            109769 
                                             101598            281921 
                                       6.56608e+006      2.82861e+006 
                                            -101598           -281921 
                                      -6.56608e+006     -2.82861e+006 
                                             23.125            23.125 
                                              271.7            272.46 
                                                500               500 
      

      【讨论】:

        【解决方案4】:

        sed 是一个出色的工具,可以在单行上进行简单的替换,但对于其他任何事情,只需使用 awk:

        $ awk '/R1/{start=NR+3;end=start+2} NR<start || NR>end' file
        R1                  30049              109769            109769
                                               101598            281921
                                         6.56608e+006      2.82861e+006
                                              -101598           -281921
                                        -6.56608e+006     -2.82861e+006
                                               23.125            23.125
                                                271.7            272.46
                                                  500               500
        

        上面说在包含 R1 (NR+3) 的行之后开始删除 3 行并在之后停止 2 行 (start+2)。如果您有其他范围或其他模式或其他条件要处理,则使其工作的调整是清晰而简单的。尝试调整 sed 解决方案以删除 20 行而不是 3 行。

        如果出于某种原因您更喜欢 sed 解决方案的简洁性,只需使用单字符变量名并去掉空格:

        awk '/R1/{s=NR+3;e=s+2}NR<s||NR>e' file
        

        它比 sed 更简洁,但仍然更易于维护、可扩展等,因为多行问题的 awk 解决方案总是如此。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-03-24
          • 2019-07-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多