文字を再帰的にsedに置き換える方法は?


13

同じシーケンスを再度繰り返すことなく、文字シーケンスの出現を再帰的に置き換えることは可能ですか?

sed次のシナリオのようにを実行すると、前述の出力を取得できます。

$ echo XX | sed -e 's/XX/XoX/g'
XoX  
$ echo XXX | sed -e 's/XX/XoX/g'
XoXX  
$ echo XXXX | sed -e 's/XX/XoX/g'
XoXXoX  

ただし、出力が次の動作に従うことを期待しています。

入力:

XX
XXX
XXXX

期待される出力:

XoX
XoXoX
XoXoXoX

sedだけで期待される動作を達成することは可能ですか?

回答:


24

できるよ:

> echo XXXX | sed -e ':loop' -e 's/XX/XoX/g' -e 't loop'
XoXoXoX

と:

  • -e ':loop' :「ループ」ラベルを作成する
  • -e 't loop' :前の置換が成功した場合、「ループ」ラベルにジャンプします

10

この特定のケースでは、先読みまたは後読みが役立ちます。GNU sedはこれらをサポートしていないと思います。でperl

perl -ne 's/X(?=X)/Xo/g; print;'

次のような先読みと先読みを使用することもできます。

s/(?<=X)(?=X)/o/g

どこ:

(?<=X)肯定的な後読み、現在の位置の前にX
(?=X)があることを確認する長さゼロのアサーション、現在の位置の後にXがあることを確認する長さゼロのアサーション

perlワンライナーで使用する:

perl -pe 's/(?<=X)(?=X)/o/g' inputfile

どこ:

-p Perlにプログラムの周りのループを仮定させ、現在の行を暗黙的に表示させます


5

ループの答えは、あなたが求めていることを行う一般的な方法です。

ただし、データの場合、GNUを使用していると仮定すると、次のことが簡単にできます。

sed 's/\B/o/g'

\bおよび\Bオプションは、正規表現の拡張機能

  • \b 単語の境界、つまり「単語」文字から「非単語」文字への遷移、またはその逆
  • \B の反対に一致します \bます。すなわち、単語の「内側」のギャップ。これにより、必要に応じて単語の内側に文字を挿入できますが、外側には文字を挿入できません。

オンラインで試す

これは、入力文字が実際にはすべて「単語」文字であると想定しています。


あるいは、GNU sedがない場合、または入力文字がすべて「単語」文字ではない場合でも、ループせずに目標を達成できます。

sed 's/./&o/g;s/o$//'

これは単にoすべての文字の後に配置し、最後の文字を削除しますoし、文字列から文字列をします。

オンラインでお試しください


1
これは、入力文字列がいくつかの数で構成されていることを前提としていXます。他のキャラクターが存在する場合、両方のソリューションが失敗します
...-AnoE

@AnoE 2番目のサンプルでは、​​の単純な置き換えで修正さXれてい.ます。編集をご覧ください。
デジタル外傷

OPが与えたケースとは異なります。彼は、必要な正確なREを与えました(ストリング内のXXの出現を変更します)。あなたのバージョンは彼が与えたものとまったく同じ入力文字列に対してのみ彼と同じ結果を与えます。汎用入力文字列用ではありません。
AnoE

4

これを実現するためのフラグがあるかどうかを確認しました。
その振る舞いがあったとしても、非常にリソースを消費します。

ただし、この特定のユースケースでは、式を2回だけ使用して必要な機能を実現することができます。すなわち、2つの繰り返しsed式を使用します。

echo XX | sed -e 's/XX/XoX/g' -e 's/XX/XoX/g'     # outputs XoX
echo XXX | sed -e 's/XX/XoX/g' -e 's/XX/XoX/g'    # outputs XoXoX
echo XXXX | sed -e 's/XX/XoX/g' -e 's/XX/XoX/g'   # outputs XoXoXoX
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.