【问题标题】:Use sed to replace patterns that are not at the start of end of lines使用 sed 替换不在行尾开头的模式
【发布时间】:2016-02-15 16:55:38
【问题描述】:

假设我有输入:

/a/b/c/d/e/
/a/b/c/d/e
a/b/c/d/e/
a/b/c/d/e

我想用+ 替换所有不在边缘的/ 所以输出是:

/a+b+c+d+e/
/a+b+c+d+e
a+b+c+d+e/
a+b+c+d+e

我试过这个命令:

sed -e "s#\(.\)/\(.\)#\1+\2#g"

接近但不完全:

/a+b/c+d/e/
/a+b/c+d/e
a+b/c+d/e/
a+b/c+d/e

大概是因为\(.\) 在连续的/ 字符之间重叠。

我不相信 sed 对行首或行尾有一个空匹配运算符。那么,这是怎么做到的呢?

【问题讨论】:

    标签: regex sed


    【解决方案1】:

    您可以将所有斜杠翻译成+,然后用斜杠替换+(在开头或结尾):

    sed 'y/\//+/;s/^+\|+$/\//g;'
    

    或者如果 OR 运算符不可用:

    sed 'y/\//+/;s/^+/\//;s/+$/\//;'
    

    最好更改分隔符以避免转义所有文字斜线:

    sed 'y~/~+~;s~^+\|+$~/~g;'
    

    或者如果 OR 运算符不可用:

    sed 'y~/~+~;s~^+~/~;s~+$~/~;'
    

    (其中^ 是行首的锚点,$ 是行尾的锚点)


    其他方式:您可以使用占位符保护要保留的斜线:

    sed 's~^/~{`%{~;s~/$~{`%{~;y~/~+~;s~{`%{~/~g;'
    

    【讨论】:

      【解决方案2】:

      如果您有 perl,您可以为此使用环视:

      perl -pe 's~(?<!^)/(?!$)~+~g' file
      

      输出:

      /a+b+c+d+e/
      /a+b+c+d+e
      a+b+c+d+e/
      a+b+c+d+e
      

      否则,您可以将此 sed 与 2 个替代品一起使用:

      sed -r 's~(.)/(.)~\1+\2~g; s~(.)/(.)~\1+\2~g' file
      

      或者这个带有标签和循环的 sed:

      sed -r ':a;s|(.)/(.)|\1+\2|g;ta' file
      

      【讨论】:

      • 或稍作改动:sed -r ':a;s|(.)/(.)|\1+\2|g;ta' file.
      • 非常感谢@Cyrus,将其添加到我的回答中
      【解决方案3】:

      这是一个 sed 命令,它可以提供您的输出:

      sed -r 's=(.)/\b=\1+=g;' file
      
      • 通常/用作s命令的分隔符,但这里我们使用=
      • / 与前面有东西 (.) 匹配,并且我们处于单词边界
      • 最初我尝试了(.)/(.),但没有奏效:
        • 第二个点被消耗,下一场比赛只会在它之后开始,
        • 即在x/y/&lt; 中,第二场比赛只会看到/z 而不是y/z
        • \b 第一个匹配不消耗y,第二个匹配看到y/

      【讨论】:

        【解决方案4】:

        这是用于执行此类工作的常见且非常有用的 sed 习惯用法:

        $ sed 's:a:aA:g; s:^/\|/$:aB:g; s:/:+:g; s:aB:/:g; s:aA:a:g' file
        /a+b+c+d+e/
        /a+b+c+d+e
        a+b+c+d+e/
        a+b+c+d+e
        

        第一个子将所有as 更改为aA。那时,输入中没有字母a,后面没有字母A(我们需要先这样做以确保在我们的第二个子之后,输入中唯一的aBs 是结果第二个子)

        第二个子将一行开头或结尾处的所有/s 更改为aB。此时,输入中唯一的 aBs 是在行首或行尾最初存在 /s 的位置。

        第三个子将所有剩余的/s(即那些不在行首或行尾的)更改为+s。

        第4个sub将aBs恢复到原来的前端/end/s。

        第5个sub将aAs恢复为原来的as。

        【讨论】:

          【解决方案5】:

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

          sed ':a;s/\([^\/]\)\/\([^\/]\)/\1+\2/g;ta' file
          

          或者视觉上更容易:

          sed -r ':a;s#([^/])/([^/])#\1+\2#g;ta' file
          

          两次确实是同一个正则表达式:

          sed 's/\([^\/]\)\/\([^\/]\)/\1+\2/g;s/\([^\/]\)\/\([^\/]\)/\1+\2/g' file
          

          【讨论】:

            猜你喜欢
            • 2021-11-10
            • 1970-01-01
            • 2013-09-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多