sed:同じ行内で特定の文字列に達すると、パターン置換の繰り返しを停止します。

sed:同じ行内で特定の文字列に達すると、パターン置換の繰り返しを停止します。

この質問に対する答えはどこにもありません。簡単に見えますが、おそらくそうではないかもしれないと思い始めました。

sedがこの文字列からSTOPの前にすべてのCATを削除するようにしたいと思います。

two CAT two four CAT CAT seven one STOP four CAT two CAT three

したがって、私が望む結果は次のとおりです。

two two four seven one STOP four CAT CAT two CAT three

文字列のどの場所にもCATがあります。停止マークはどこにあっても構いませんが、次のいずれかを使用でき、常にSTOPとしてマークされます。

(編集:以下に指摘したように、私の質問は不明です。CATには隣接する空白がなければなりませんか、それとも境界でどんな文字でも持つことができますか?英数字以外の文字しかありませんか?です。 大きな bash 関数) 単純化しすぎているので、以下の解決策は隣接関係について別の仮定を行うことができることを読者に覚えておいてください。ありがとうございます)

答え1

CAT以前のsがなくなるまで、ループ内で一度に1つずつ置き換えることができますSTOP

$ echo 'two CAT two four CAT CAT seven one STOP four CAT two CAT three' |
    sed -e :a -e '/CAT.*STOP/s/CAT //;ta'
two two four seven one STOP four CAT two CAT three

答え2

いくつかの奇妙な場合:

awk '{while($0~/CAT .*STOP/)sub(/CAT /,"")}1' file
$ echo 'two CAT two four CAT CAT seven one STOP four CAT two CAT three' |
  awk '{while($0~/CAT .*STOP/)sub(/CAT /,"")}1'
two two four seven one STOP four CAT two CAT three

答え3

そしてperl

perl -pe 's/CAT (?=.*STOP)//g'

CATSTOP次の行が存在する場合にのみ置き換えられます。

答え4

(これがsedパズルよりも重要な場合は、sedを使用してまったく使用しないことをお勧めします。ここのあいまいな答えとは異なり、Pythonではこれを簡単かつ非常に明確に書くことができます。)

以下のように、sedでループを使用できます。コードの下に指示と注意事項があります。

s/STOP/@/
: loop
s/^\([^@]*\)CAT\(.*\)$/\1\2/
t loop
s/@/STOP/
p

次のように実行

$ sed -n -f t.sed

説明したように、すべての行を変更します。存在しない場合は、入力行からすべての項目を削除するようにSTOPコードが書かれています。CATまた、このコードはこれが@入力行に表示されないと仮定します。その場合は、他のマーカー文字を探す必要があります。


どうしたの?コードを見てみましょう。

s/STOP/@/

存在しない項目に一致する正規表現を作成することは困難ですsed。ただし、単一文字の場合(たとえば、操作を実行するx場合)は例外です。[^x]*したがって、私たちのセンチナルをSTOP行の残りの部分で使用されていない単一の文字に置き換えてください。そのような性質がなければ、人生はさらに困難になり、これがsed実際に作業に適したツールではないことを覚えています。

: loop
s/^\([^@]*\)CAT\(.*\)$/\1\2/
t loop

これが重要な部分です。: loop後で再分岐できるタグをsedスクリプトで宣言してください。次に、その行で前にないタグをs///見つけて置き換え、前後のテキストを保持します。置換が発生した場合は、戻ってもう一度やり直してください。交換が失敗した場合、つまり交換が見つからない場合、返された分岐は使用されません。CAT@t looploopCATloop

s/@/STOP/
p

実際のSTOPテキストを復元し、最後の行を印刷します。

関連情報