web-dev-qa-db-ja.com

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

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

以下のシナリオのように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だけで期待される動作を実現することは可能ですか?

13

できるよ:

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

と:

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

この特定のケースでは、先読みまたは後読みが役立ちます。 GNU sedはこれらをサポートしていません。Perlの場合:

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

次のように lookbehind and lookahead を使用することもできます。

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

どこ:

(?<=X)は肯定的な後読みであり、現在の位置の前にXがあることを確認する長さゼロのアサーションです。
(?=X)はポジティブルックアヘッド、つまり現在の位置の後にXがあることを確認する長さゼロのアサーションです

Perlワンライナーでの使用:

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

どこ:

-pは、Perlが現在の行を暗黙的に出力するプログラムをループすることを想定します。

10

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

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

sed 's/\B/o/g'

\bおよび\Bオプションは regex extensions です。

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

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

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


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

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

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

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

5
Digital Trauma