web-dev-qa-db-fra.com

Comment remplacer récursivement des personnages avec sed?

Est-il possible de remplacer de manière récursive les occurrences d'une séquence de caractères sans effectuer de nouvelle itération sur la même séquence?

En effectuant une sed comme dans les scénarios suivants, je peux obtenir le résultat mentionné.

$ 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  

Cependant, je m'attends à ce que la sortie présente le comportement suivant.

Contribution:

XX
XXX
XXXX

Production attendue:

XoX
XoXoX
XoXoXoX

Est-il possible d'obtenir le comportement attendu avec sed seul?

13
Ishan Madhusanka

Tu peux faire:

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

Avec:

  • -e ':loop': Créer une étiquette "boucle"
  • -e 't loop': Aller au libellé "loop" si la substitution précédente a réussi
24
Gohu

Dans ce cas particulier, il serait utile de prévoir ou de regarder en arrière. Je pense que GNU sed ne les prend pas en charge. Avec Perl:

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

Vous pouvez également utiliser lookbehind et lookahead comme:

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

Où:

(?<=X) est une observation positive, une assertion de longueur nulle qui assure que nous avons un X avant la position actuelle
(?=X) est une anticipation positive, une assertion de longueur nulle qui garantit que nous avons un X après la position actuelle

Utilisation dans un Perl one-liner:

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

Où:

-p oblige Perl à supposer une boucle autour du programme avec une impression implicite de la ligne en cours

10
Kamil Maciorowski

La réponse en boucle est la manière générale de faire ce que vous demandez.

Cependant, dans le cas de vos données, en supposant que vous utilisez GNU, vous pouvez simplement faire:

sed 's/\B/o/g'

Les options \b et \B sont les extensions regex :

  • \b correspond aux limites du mot, c.-à-d. la transition d’un caractère "Word" à un caractère "non-Word", ou inversement
  • \B correspond à l'opposé de \b. c'est-à-dire les lacunes "à l'intérieur" des mots. Cela nous permet d’insérer des caractères dans un mot mais pas à l’extérieur, comme requis.

Essayez-le en ligne .

Cela suppose que les caractères saisis sont en fait tous des caractères "Word".


Alternativement, si vous n'avez pas GNU sed, ou si les caractères saisis ne sont pas tous des caractères "Word", vous pouvez toujours atteindre votre objectif sans passer en boucle:

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

Cela place simplement une o après chaque caractère, puis supprime la dernière o de la chaîne.

Essayez-le en ligne .

5
Digital Trauma

J'ai vérifié s'il y avait une sorte de drapeau pour y arriver.
Même si ce comportement existait déjà, cela consommerait énormément de ressources.

Cependant, dans ce cas d'utilisation particulier, il est possible d'avoir l'expression deux fois et d'obtenir les fonctionnalités requises. c'est-à-dire avec 2 expressions sed répétées.

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
4
Ishan Madhusanka