Wie kann ich den gesamten Text zwischen verschachtelten geschweiften Klammern in einer mehrzeiligen Textdatei löschen?


9

Diese Frage stammt von Wie kann ich den gesamten Text in geschweiften Klammern in einer mehrzeiligen Textdatei löschen? (trotzdem, aber ohne die Anforderungen für die Verschachtelung).

Beispiel:

This is {
{the multiline
text} file }
that wants
{ to {be
changed}
} anyway.

Soll werden:

This is 
that wants
 anyway.

Ist es möglich, dies mit einem einzeiligen Bash-Befehl (awk, sed, perl, grep, cut, tr ... usw.) zu tun?

Antworten:


13
$ sed ':again;$!N;$!b again; :b; s/{[^{}]*}//g; t b' file3
This is 
that wants
 anyway.

Erläuterung:

  • :again;$!N;$!b again

    Dies liest die gesamte Datei ein.

    :againist ein Etikett. Nliest in der nächsten Zeile und $!Nliest in der nächsten Zeile unter der Bedingung, dass wir nicht bereits in der letzten Zeile sind. $!b againverzweigt zurück zum againEtikett, sofern dies nicht die letzte Zeile ist.

  • :b

    Dies definiert eine Beschriftung b.

  • s/{[^{}]*}//g

    Dadurch wird Text in geschweiften Klammern entfernt, solange der Text keine inneren Klammern enthält.

  • t b

    Wenn der obige Ersatzbefehl zu einer Änderung geführt hat, kehren Sie zur Bezeichnung zurück b. Auf diese Weise wird der Ersatzbefehl wiederholt, bis alle Klammergruppen entfernt sind.


3

Ein Perl-Ansatz:

$ perl -F"" -a00ne 'for (@F){$i++ if /{/; $i||print; $i-- if /}/}' file
This is 
that wants
 anyway

Erläuterung

  • -a: Aktiviert die automatische Aufteilung des von -Fin das @FArray angegebenen Dateibegrenzers .
  • -F"": setzt das Eingabefeldtrennzeichen auf leer, was dazu führt, dass jedes Element @Feines der Eingabezeichen ist.
  • -00: Aktivieren Sie den "Absatzmodus", in dem eine "Zeile" als zwei aufeinanderfolgende Zeilenumbrüche definiert ist. Dies bedeutet, dass in diesem Fall die gesamte Datei als einzelne Zeile behandelt wird. Wenn Ihre Datei viele Absätze enthalten kann und die Klammern mehrere Absätze umfassen können, verwenden Sie -0777stattdessen.
  • -ne: Lesen Sie eine Eingabedatei und wenden Sie das angegebene Skript -eauf jede Zeile an.

Das Skript selbst ist eigentlich recht einfach. Ein Zähler wird jedes Mal, wenn a {gesehen wird, um eins erhöht und für jeden um eins dekrementiert }. Das heißt, wenn der Zähler 0 ist, befinden wir uns nicht in Klammern und sollten drucken:

  • for (@F){}: Tun Sie dies für jedes Element von @F, jedes Zeichen in der Zeile.
  • $i++ if /{/;: $ium eins erhöhen, wenn dieses Zeichen a ist{
  • $i||print;: Drucken, sofern nicht $igesetzt (0 gilt als nicht gesetzt).
  • $i-- if /}/: Dekrementiere $ium eins, wenn dieses Zeichen a ist}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.