Puoi fare:
> echo XXXX | sed -e ':loop' -e 's/XX/XoX/g' -e 't loop'
XoXoXoX
Con:
-e ':loop'
:Crea un'etichetta "loop"-e 't loop'
:passa all'etichetta "loop" se la sostituzione precedente ha avuto successo
In questo caso particolare sarebbe utile guardare avanti o guardare dietro. Penso che GNU sed
non li supporta. Con perl
:
perl -ne 's/X(?=X)/Xo/g; print;'
Puoi anche usare lookbehind e lookahead come:
s/(?<=X)(?=X)/o/g
Dove:
(?<=X)
è un lookbehind positivo, un'asserzione di lunghezza zero che assicura che abbiamo una X prima della posizione corrente
(?=X)
è un lookahead positivo, un'asserzione di lunghezza zero che assicura che abbiamo una X dopo la posizione corrente
Usando in un one-liner perl:
perl -pe 's/(?<=X)(?=X)/o/g' inputfile
Dove:
-p
fa sì che Perl assuma un ciclo attorno al programma con una stampa implicita della riga corrente
La risposta ciclica è il modo generale per fare ciò che stai chiedendo.
Tuttavia, nel caso dei tuoi dati, supponendo che tu stia usando GNU, puoi semplicemente fare:
sed 's/\B/o/g'
Il \b
e \B
opzioni sono estensioni regex:
\b
corrisponde ai limiti delle parole, ovvero la transizione da un carattere "parola" a un carattere "non parola" o viceversa\B
corrisponde all'opposto di\b
. cioè le lacune "dentro" le parole. Questo ci permette di inserire caratteri all'interno di una parola ma non all'esterno, come richiesto.
Provalo online.
Ciò presuppone che i caratteri immessi siano in realtà tutti caratteri "parola".
In alternativa, se non hai GNU sed, o se i caratteri di input non sono tutti caratteri "parola", puoi comunque raggiungere il tuo obiettivo senza loop:
sed 's/./&o/g;s/o$//'
Questo inserisce semplicemente un o
dopo ogni carattere e quindi rimuove il o
finale dalla stringa.
Provalo online.