同じシーケンスを再度繰り返すことなく、文字シーケンスの出現を再帰的に置き換えることはできますか?
以下のシナリオのように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だけで期待される動作を実現することは可能ですか?
できるよ:
> echo XXXX | sed -e ':loop' -e 's/XX/XoX/g' -e 't loop'
XoXoXoX
と:
-e ':loop'
:「ループ」ラベルを作成します-e 't loop'
:以前の置換が成功した場合、「ループ」ラベルにジャンプしますこの特定のケースでは、先読みまたは後読みが役立ちます。 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が現在の行を暗黙的に出力するプログラムをループすることを想定します。
ループする答えは、あなたが求めていることを行うための一般的な方法です。
ただし、データの場合、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
を文字列から削除するだけです。