代替sed
,您总是可以awk
在每字符字段模式 ( FS=""
) 中使用:
awk 'BEGIN {
RS = "\n" ;
FS = "" ;
d = 0 ;
}
{
for (i=1; i<=NF; i++)
if ($i == "{") {
d++ ;
if (d == 1) printf "{\n"
} else
if ($i == "}") {
d-- ;
if (d == 0) printf "}"
} else
if (d == 0)
printf "%s", $i ;
if (d == 0) printf "\n"
}' INPUT-FILE(s)...
以上将跳过任何成对的花括号的内容,即函数和结构体、数组初始化等,并将结果输出到标准输出。您可以指定一个或多个文件。(如果您不指定任何文件,它将期望来自标准输入的输入。)
就像现在一样,它会对引号或注释中的大括号感到困惑。这可以以相同的方式修复,但它确实很快变得相当复杂。这只是一个让你大部分时间的技巧。
我添加了分号 ( ;
),因此您可以将上述代码段中的所有内容都填入一个长命令行中。
脚本的逻辑非常简单。它使用空字段分隔符 ( FS
),因此输入中的每个字符都是它们自己的字段。该BEGIN
规则在处理任何输入之前运行一次,并设置它。对于开发人员信息,我也进行了初始化,d = 0
尽管 awk 没有必要,因为它假定未初始化的变量为空或适当的零。它将跟踪每个输入字符的当前大括号深度。
第二个大括号表达式将每条记录执行一次。由于我设置RS = "\n"
了,每一行都是一个单独的表达式。因此,它将在每个输入行执行一次。由于FS = ""
,该行上的每个字符将是一个单独的字段。记录中有NF
字段:$1
, $2
, .., $(NF-1)
, 和$NF
. 由三部分组成的 if 子句仅输出最外面的大括号,以及不在大括号内的所有内容(即 when d == 0
)。
可以扩展此awk
scriptlet 以包含注释、字符串、字符常量(用于\047
引用单引号,除非您使用 将脚本放入单独的文件中#!/usr/bin/awk -f
),并处理或忽略预处理器宏。
它确实有点复杂,你最终会得到几百行 awk 脚本,但它应该非常可靠且相当快。之所以可能,是因为在这种特殊情况下,C 中的标记化规则很容易遵循;我个人会在所有其他用例中使用成熟的 C 词法分析器(词法分析器或扫描器)。可能也是为了这个。
如果你想使用成熟的 C 词法分析器,网上有很多免费的,但你必须使用更高级的语言,如 C 或 C++。如果您希望处理所有极端情况,它也需要合并一个 C/C++ 预处理器,但这些规则很容易(即使使用 awk)。