Comment supprimer tout le texte entre des accolades imbriquées dans un fichier texte multiligne?


9

Cette question vient de Comment puis-je supprimer tout le texte entre accolades dans un fichier texte multiligne? (tout de même, mais sans les exigences d'imbrication).

Exemple:

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

Devrait devenir:

This is 
that wants
 anyway.

Est-il possible de le faire avec une sorte de commande bash en ligne (awk, sed, perl, grep, cut, tr ... etc)?

Réponses:


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

Explication:

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

    Cela se lit dans tout le fichier.

    :againest une étiquette. Nlit dans la ligne suivante et $!Nlit dans la ligne suivante à condition que nous ne soyons pas déjà à la dernière ligne. $!b againramène à l' againétiquette à condition que ce ne soit pas la dernière ligne.

  • :b

    Cela définit une étiquette b.

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

    Cela supprime le texte entre accolades tant que le texte ne contient pas d'accolades internes.

  • t b

    Si la commande de substitution ci-dessus a entraîné une modification, revenez à l'étiquette b. De cette façon, la commande de substitution est répétée jusqu'à ce que tous les groupes d'accolades soient supprimés.


3

Une approche Perl:

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

Explication

  • -a: active le fractionnement automatique sur le délimiteur de fichier donné par -Fdans le @Ftableau.
  • -F"": définit le séparateur de champ de saisie sur vide, ce qui fera que chaque élément @Fsera l'un des caractères d'entrée.
  • -00: activer le "mode paragraphe", où une "ligne" est définie comme deux caractères de nouvelle ligne consécutifs. Cela signifie que le fichier entier dans ce cas sera traité comme une seule ligne. Si votre fichier peut contenir plusieurs paragraphes et que les crochets peuvent s'étendre sur plusieurs paragraphes, utilisez -0777plutôt.
  • -ne: lire un fichier d'entrée et appliquer le script donné par -eà chaque ligne.

Le script lui-même est en fait assez simple. Un compteur est incrémenté de un à chaque fois que a {est vu et décrémenté de un pour chaque }. Cela signifie que lorsque le compteur est à 0, nous ne sommes pas entre crochets et devons imprimer:

  • for (@F){}: faites cela pour chaque élément de @F, chaque caractère de la ligne.
  • $i++ if /{/;: incrémenter $ide un si ce caractère est un{
  • $i||print;: imprimer sauf si $iest défini (0 compte comme non défini).
  • $i-- if /}/: décrémente $ide un si ce caractère est un}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.