How to recursively replace characters with sed?

Is it possible to replace occurrences of a character sequence recursively without iterating over the same sequence again?

By performing a sed as in the following scenarios I can get the mentioned output.

$ 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  

However, I'm expecting the output to follow the following behavior.

Input:

XX
XXX
XXXX

Expected output:

XoX
XoXoX
XoXoXoX

Is it possible to achieve the expected behavior with sed alone?


Solution 1:

You can do:

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

With:

  • -e ':loop' : Create a "loop" label
  • -e 't loop' : Jump to the "loop" label if previous substitution was successful

Solution 2:

In this particular case look-ahead or look-behind would be useful. I think GNU sed doesn't support these. With perl:

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

You could also use lookbehind and lookahead like:

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

Where:

(?<=X) is a positive lookbehind, a zero-length assertion that make sure we have an X before the current position
(?=X) is a positive lookahead, a zero-length assertion that make sure we have an X after the current position

Using in a perl one-liner:

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

Where:

-p causes Perl to assume a loop around the program with an implicit print of the current line