Wie ersetze ich rekursiv Zeichen durch sed?

13

Ist es möglich, Vorkommen einer Zeichenfolge rekursiv zu ersetzen, ohne dieselbe Folge erneut zu durchlaufen?

Durch Ausführen eines sedwie in den folgenden Szenarien kann ich die erwähnte Ausgabe erhalten.

$ 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  

Ich erwarte jedoch, dass die Ausgabe dem folgenden Verhalten folgt.

Eingang:

XX
XXX
XXXX

Erwartete Ausgabe:

XoX
XoXoX
XoXoXoX

Kann man mit sed alleine das erwartete Verhalten erreichen?

Ishan Madhusanka
quelle

Antworten:

24

Du kannst tun:

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

Mit:

  • -e ':loop' : Erstellen Sie ein "Loop" -Label
  • -e 't loop' : Springen Sie zum Label "loop", wenn die vorherige Ersetzung erfolgreich war
Gohu
quelle
10

In diesem speziellen Fall wäre ein Blick nach vorn oder nach hinten nützlich. Ich denke, GNU sedunterstützt diese nicht. Mit perl:

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

Sie können auch lookbehind und lookahead wie folgt verwenden :

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

Wo:

(?<=X)ist ein positiver Lookbehind, eine Zusicherung der Länge Null, die sicherstellt, dass wir ein X vor der aktuellen Position haben.
(?=X)ist ein positiver Lookahead, eine Zusicherung der Länge Null, die sicherstellt, dass wir ein X nach der aktuellen Position haben

Verwendung in einem Perl-Einzeiler:

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

Wo:

-p Bewirkt, dass Perl eine Schleife um das Programm mit einem impliziten Ausdruck der aktuellen Zeile annimmt

Toto
quelle
5

Die Schleifenantwort ist die allgemeine Methode, um das zu tun, wonach Sie fragen.

Wenn Sie jedoch GNU verwenden, können Sie bei Ihren Daten einfach Folgendes tun:

sed 's/\B/o/g'

Die Optionen \bund \Bsind reguläre Ausdrücke :

  • \b Entspricht Wortgrenzen, dh dem Übergang von einem "Wort" -Zeichen zu einem "Nicht-Wort" -Zeichen oder umgekehrt
  • \Bentspricht dem Gegenteil von \b. dh die Lücken "in" Worten. Auf diese Weise können wir nach Bedarf Zeichen innerhalb eines Wortes, jedoch nicht außerhalb einfügen.

Probieren Sie es online aus .

Dies setzt voraus, dass die eingegebenen Zeichen tatsächlich alle "Wort" -Zeichen sind.


Alternativ können Sie Ihr Ziel auch ohne Schleife erreichen, wenn Sie GNU sed nicht haben oder wenn die eingegebenen Zeichen nicht alle "Wort" -Zeichen sind:

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

Dies setzt einfach ein onach jedem Zeichen und entfernt dann das Finale oaus der Zeichenkette.

Probieren Sie es online aus .

Digitales Trauma
quelle
1
Dies setzt voraus, dass die Eingabezeichenfolgen aus einer bestimmten Anzahl Xund nichts anderem bestehen. Beide Lösungen
schlagen
@AnoE Im zweiten Beispiel wird dies durch einfaches Ersetzen von Xby behoben .. Bitte siehe Bearbeiten.
Digitales Trauma
Nicht gleichbedeutend mit dem Fall, den das OP gegeben hat. Er gab die exakten REs an, die er benötigte (das Vorkommen von XX in einer Zeichenkette ändern). Ihre Versionen liefern nur dasselbe Ergebnis wie seine für genau dieselben Eingabezeichenfolgen, die er angegeben hat. Nicht für generische Eingabezeichenfolgen.
AnoE
4

Ich habe geprüft, ob es irgendeine Art von Flagge gibt, die dies ermöglicht.
Selbst wenn dieses Verhalten vorliegt, wird es sehr ressourcenintensiv sein.

In diesem speziellen Anwendungsfall ist es jedoch möglich, den Ausdruck nur zweimal zu haben und die erforderliche Funktionalität zu erzielen. dh mit 2 sich wiederholenden sedAusdrücken.

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