Come posso eliminare tutto il testo tra parentesi graffe nidificate in un file di testo multilinea?


9

Questa domanda viene da Come posso eliminare tutto il testo tra parentesi graffe in un file di testo multilinea? (lo stesso, ma senza i requisiti per l'annidamento).

Esempio:

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

Dovrebbe diventare:

This is 
that wants
 anyway.

È possibile farlo con una sorta di comando bash su una riga (awk, sed, perl, grep, cut, tr ... etc)?

Risposte:


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

Spiegazione:

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

    Questo si legge in tutto il file.

    :againè un'etichetta. Nlegge nella riga successiva e $!Nlegge nella riga successiva a condizione che non siamo già all'ultima riga. $!b againsi ramifica di nuovo againsull'etichetta a condizione che questa non sia l'ultima riga.

  • :b

    Questo definisce un'etichetta b.

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

    Ciò rimuove il testo tra parentesi graffe purché il testo non contenga parentesi graffe interne.

  • t b

    Se il comando sostitutivo sopra riportato ha comportato una modifica, tornare all'etichetta b. In questo modo, il comando sostitutivo viene ripetuto fino alla rimozione di tutti i gruppi di parentesi graffe.


3

Un approccio Perl:

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

Spiegazione

  • -a: Attiva splitting automatico sul file delimitatore data dal -Fnella @Fmatrice.
  • -F"": imposta il separatore del campo di input su vuoto, il che comporterà che ogni elemento @Fsia uno dei caratteri di input.
  • -00: attiva la "modalità paragrafo", in cui una "linea" è definita come due caratteri di nuova riga consecutivi. Ciò significa che l'intero file in questo caso verrà trattato come una singola riga. Se il tuo file può avere molti paragrafi e le parentesi possono estendersi su più paragrafi, usa -0777invece.
  • -ne: legge un file di input e applica lo script fornito da -eciascuna riga.

Lo script stesso è in realtà abbastanza semplice. Un contatore viene incrementato di uno ogni volta che {viene visto e diminuito di uno per ogni }. Ciò significa che quando il contatore è 0, non ci troviamo tra parentesi e dovremmo stampare:

  • for (@F){}: esegui questa operazione per ogni elemento di @F, ogni carattere nella riga.
  • $i++ if /{/;: incrementa $idi uno se questo carattere è a{
  • $i||print;: stampa a meno che non $isia impostato (0 viene conteggiato come non impostato).
  • $i-- if /}/: decrementa $idi uno se questo personaggio è a}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.