如何删除多行文本文件中嵌套大括号之间的所有文本?

如何删除多行文本文件中嵌套大括号之间的所有文本?

这个问题来自 如何删除多行文本文件中大括号之间的所有文本?(一样,但是没有嵌套的要求)。

例子:

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

应该变成:

This is 
that wants
 anyway.

是否可以使用某种单行 bash 命令(awk、sed、perl、grep、cut、tr...等)来完成此操作?

答案1

$ 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

    如果上述替换命令导致更改,请跳回 label b。这样,重复替换命令,直到删除所有大括号组。

答案2

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到每一行。

脚本本身实际上非常简单。每次看到 a 时,计数器就会加一{,并且每次看到 都会减一}。这意味着当计数器为 0 时,我们不在括号内,应该打印:

  • for (@F){}:对@F行中的每个元素、每个字符执行此操作。
  • $i++ if /{/;$i如果该字符是一个则加一{
  • $i||print;:打印除非$i已设置(0 视为未设置)。
  • $i-- if /}/$i如果该字符是一个则减一}

相关内容