Wie ersetze ich Charaktere rekursiv durch sed?

1722
Ishan Madhusanka

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

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?

13

4 Antworten auf die Frage

23
Gohu

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' : Springe zum Label "Schleife", wenn die vorherige Ersetzung erfolgreich war
10
Kamil Maciorowski

In diesem speziellen Fall wäre Vorausschau oder Rückblick hilfreich. Ich denke, GNU sedunterstützt diese nicht. Mit perl:

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

Sie könnten auch lookbehind und lookahead verwenden :

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

Woher:

(?<=X)ist ein positiver Look hinter, eine Zusicherung der Länge Null, die sicherstellt, dass wir ein X haben, bevor die aktuelle Position eine positive Vorausschau ist, eine Zusicherung der Länge
(?=X)Null, die sicherstellt, dass nach der aktuellen Position ein X steht

Verwendung in einem Perl-Einzeiler:

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

Woher:

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

5
Digital Trauma

Die Antwort auf die Schleife ist der allgemeine Weg, um das zu tun, was Sie fragen.

Wenn Sie jedoch GNU verwenden, können Sie Folgendes tun:

sed 's/\B/o/g' 

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

  • \b passt zu 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" Wörtern. Dies erlaubt uns, Zeichen in ein Wort einzufügen, aber nicht außerhalb, je nach Bedarf.

Probieren Sie es online aus .

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


Alternativ, wenn Sie nicht über GNU sed verfügen oder wenn die Eingabezeichen nicht alle "Wort" -Zeichen sind, können Sie Ihr Ziel auch ohne Schleife erreichen:

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

Dies setzt einfach ein oZeichen nach jedem Zeichen und entfernt dann das Finale oaus der Zeichenfolge.

Probieren Sie es online aus .

Dies setzt voraus, dass Eingabestrings aus einer Anzahl von 'X' bestehen und nichts anderes. Beide Lösungen schlagen fehl, wenn andere Zeichen vorhanden sind ... AnoE vor 5 Jahren 1
@AnoE In der zweiten Probe wird das mit einem einfachen Ersetzen von 'X' durch '.' Behoben. Bitte siehe Bearbeiten. Digital Trauma vor 5 Jahren 0
Nicht gleichbedeutend mit dem Fall, den das OP gegeben hat. Er gab genau die benötigten REs an (veränderte Vorkommen von XX in einer Zeichenfolge). Ihre Versionen geben nur das gleiche Ergebnis wie seine für dieselbe Eingabezeichenfolge, die er angegeben hat. Nicht für generische Eingabezeichenfolgen. AnoE vor 5 Jahren 0
4
Ishan Madhusanka

Ich habe geprüft, ob es eine Art Flagge gibt, die dies ermöglicht.
Selbst wenn dieses Verhalten dort war, 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 erreichen. 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