必要な数の単語を置き換える[閉じる]

必要な数の単語を置き換える[閉じる]

を使用して、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コマンドについて言及する2つのことがあります。

  • \<単語の境界と\>一致しますが、次の基準でのみグループ化しようとしています。\(\)
  • 文字の直接マッピングを変更するには、複数の置換の代わりにy変換コマンドを使用できます

おすすめ記事