替换任意数量的单词

替换任意数量的单词

使用sed,我想按以下方式替换模式:

---          >>>         +++
--+--        >>>         ++-++
--+-+--      >>>         ++-+-++
--+-+-+--    >>>         ++-+-+-++

...

--(+-)^n-    >>>         ++(-+)^n+

我正在操作的字符串是 + 和 - 的任意列表。

--+++-+--+--++-+--++--+-+--++--+-++-+-

我尝试过这个,但它不起作用。

sed '/--\<+-\>*-/{s/+/A/g;s/-/+/g;s/A/-/g}'

对于上面的示例,我期望以下输出:

--+++-+--+--++-+--++--+-+--++--+-++-+-     (input)
--+++-+++-++++-+--++++-+-++++--+-++-+-     (output)
       !!!!!        !!!!!!!

(感叹号表示更改的区域。)

答案1

您尝试仅修改地址中正则表达式匹配的部分,但是一旦地址匹配,替换就会影响整行。诀窍是当您应用变换时,仅在模式空间中包含您想要更改的内容。这个命令的作用是:

sed '/--\(+-\)*-/{:a;h;s/.*\(--\(+-\)*-\).*/\1/;y/+-/-+/;G;s/\(.*\)\n\(.*\)--\(+-\)*-\(.*\)/\2\1\4/;/--\(+-\)*-/ba}' <<< '--+++-+--+--++-+--++--+-+--++--+-++-+-'

一点更容易阅读:

/--\(+-\)*-/ {                  # Match a line containing the pattern
    :start                      # Label to branch back to
    h                           # Copy pattern space to hold space
    s/.*\(--\(+-\)*-\).*/\1/    # Remove everything but pattern
    y/+-/-+/                    # Swap + and -
    G                           # Append hold space to pattern space
    s/\(.*\)\n\(.*\)--\(+-\)*-\(.*\)/\2\1\4/  # Rearrange pattern space
    /--\(+-\)*-/b start         # If there are more occurrences, branch to start
}

请注意,这可能不适用于评论,y似乎有问题。

使用示例字符串进行测试:

$ sed -f sedscr <<< '--+++-+--+--++-+--++--+-+--++--+-++-+-'
--+++-+++-++++-+--++++-+-++++--+-++-+-

关于问题中的 sed 命令有两点需要提及:

  • \<\>匹配单词边界,但您只想分组:\(\)
  • 如果要更改字符的直接映射,则可以使用转换命令y而不是多次替换

相关内容