Как удалить весь текст между вложенными фигурными скобками в многострочном текстовом файле?

9

Этот вопрос возникает из Как я могу удалить весь текст в фигурных скобках в многострочном текстовом файле? (точно так же, но без требований по вложенности).

Пример:

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

Должно стать:

This is 
that wants
 anyway.

Возможно ли сделать это с помощью какой-то однострочной команды bash (awk, sed, perl, grep, cut, tr ... и т. Д.)?

Сопалахо де Арриерес
источник

Ответы:

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

Объяснение:

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

    Это читается во всем файле.

    :againэто ярлык. Nчитает в следующей строке и $!Nчитает в следующей строке при условии, что мы еще не в последней строке. $!b againвозвращается к againметке при условии, что это не последняя строка.

  • :b

    Это определяет метку b.

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

    Это удаляет текст в фигурных скобках, если текст не содержит внутренних фигурных скобок.

  • t b

    Если приведенная выше команда замены привела к изменению, вернитесь к метке b. Таким образом, команда замещения повторяется до тех пор, пока все группы скобок не будут удалены.

John1024
источник
3

Подход Perl:

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

объяснение

  • -a: включает автоматическое разбиение по разделителю файла, заданному -Fв @Fмассиве.
  • -F"": устанавливает пустой разделитель поля ввода, в результате чего каждый элемент @Fстановится одним из символов ввода.
  • -00: включить «режим абзаца», где «строка» определяется как два последовательных символа новой строки. Это означает, что весь файл в этом случае будет рассматриваться как одна строка. Если в вашем файле может быть много абзацев, а скобки могут занимать несколько абзацев, используйте -0777вместо этого.
  • -ne: прочитайте входной файл и примените скрипт, заданный -eдля каждой строки.

Сам сценарий на самом деле довольно прост. Счетчик увеличивается на единицу каждый раз, когда {видно, и уменьшается на единицу для каждого }. Это означает, что когда счетчик равен 0, мы не в скобках и должны вывести:

  • for (@F){}: сделать это для каждого элемента @F, каждого символа в строке.
  • $i++ if /{/;: увеличение $iна единицу, если этот символ{
  • $i||print;: печать, если $iне установлено (0 считается неустановленным).
  • $i-- if /}/: уменьшение $iна единицу, если этот символ}
Тердон
источник