![将所有 C 注释打印到单独的文本文件中](https://linux22.com/image/227984/%E5%B0%86%E6%89%80%E6%9C%89%20C%20%E6%B3%A8%E9%87%8A%E6%89%93%E5%8D%B0%E5%88%B0%E5%8D%95%E7%8B%AC%E7%9A%84%E6%96%87%E6%9C%AC%E6%96%87%E4%BB%B6%E4%B8%AD.png)
我想将所有 C 注释打印到单独的文本文件中。
- 使用 awk、sed、grep 或 bash
- 输出 /* ... */ 之间的所有多行 C 注释(包含)
- 带有 // 注释的输出行
- 可选:打印行号
我尝试了这些解决方案,但在 Ubuntu 上不起作用
我的请求的目的是能够快速使用源代码注释作为良好文档的起点。我不喜欢专用文档程序的额外混乱和专有嵌入式命令(即 Doxygen)。例如,正确注释每个源代码函数并删除表面的一行注释将节省大量时间,并提供近乎完整的参考。这也将鼓励更好的源代码注释。
答案1
已经有很多使用 shell-magic 的答案,但我认为通过使用您可能已经拥有的工具可以更容易地完成。即,海湾合作委员会。
diff -u <(gcc -fpreprocessed -dD -E main.c) main.c | grep '^+' | cut -c 2-
怎么运行的?
gcc -fpreprocessed -dD -E main.c
删除文件中的所有注释并将其放在标准输出上diff -u <(...) main.c
从 stdout 获取输入并将其与原始数据进行比较grep '^+'
过滤以 . 开头的所有行+
。换句话说:过滤之前确定的评论cut -c 2-
+
从输出中 删除符号
不需要超级复杂的正则表达式、perl 或 awk 的东西,同时还涵盖其他答案可能错过的所有边缘情况。
答案2
如果您考虑以下因素,这并不像看起来那么微不足道:puts("string with /*")
记住"
s 可以出现在 中ch = '"'
。
或者续行:
printf("..."); /\
* yes, this is a comment */
/\
/ and this as well
或者三字母组。
为了解决这些问题,我们可以调整这是对相反问题的回答使其打印而不是删除注释:
perl -0777 -pe '
s{
(?<comment>
# /* ... */ C comments
/ (?<lc> # line continuation
(?<bs> # backslash in its regular or trigraph form
\\ | \?\?/
)
(?: \n | \r\n?) # handling LF, CR and CRLF line delimiters
)* \* .*? \* (?&lc)* /
| / (?&lc)* / (?:(?&lc) | [^\r\n])* # // C++/C99 comments
) |
"(?:(?&bs)(?&lc)*.|.)*?" # "strings" literals
| '\''(?&lc)*(?:(?&bs)(?&lc)*(?:\?\?.|.))?(?:\?\?.|.)*?'\'' # (w)char literals
| \?\?'\'' # trigraph form of ^
| .[^'\''"/?]* # anything else
}{$+{comment} eq "" ? "" : "$+{comment}\n"}exsg'
在另一个问题中的人为示例中,涵盖了大多数极端情况:
#include <stdio.h>
int main()
{
printf("%d %s %s %c%c%c%c%c %s %s %d\n",
1-/* comment */-1,
/\
* comment */
"/* not a comment */",
/* multiline
comment */
// comment
/\
/ comment
// multiline\
comment
"// not a comment",
'"' /* comment */ , '"',
'\'','"'/* comment */,
'\
\
"', /* comment */
"\\
" /* not a comment */ ",
"??/" /* not a comment */ ",
'??''+'"' /* "comment" */);
return 0;
}
给出:
/* comment */
/\
* comment */
/* multiline
comment */
// comment
/\
/ comment
// multiline\
comment
/* comment */
/* comment */
/* comment */
/* "comment" */
为了获取行号,因为我们在 slurp 模式下运行,其中主题是整个输入,而不是一次处理一行输入,所以有点棘手。我们可以通过使用(?{code})
正则表达式运算符在每次找到行分隔符(C 中的 CR、LF 或 CRLF)时增加计数器来做到这一点:
perl -0777 -pe '
s{
(?<comment>(?{$l=$n+1})
/
(?<lc> # line continuation
(?<bs> # backslash in its regular or trigraph form
\\ | \?\?/
) (?<nl>(?:\n|\r\n?) (?{$n++})) # handling LF, CR and CRLF line delimiters
)*
(?:
\* (?: (?&nl) | .)*? \* (?&lc)* / # /* ... */ C comments
| / (?:(?&lc) | [^\r\n])* # // C++/C99 comments
)
) |
"(?:(?&bs)(?&lc)*.|.)*?" # "strings" literals
| '\''(?&lc)*(?:(?&bs)(?&lc)*(?:\?\?.|.))?(?:\?\?.|.)*?'\'' # (w)char literals
| \?\?'\'' # trigraph form of ^
| (?&nl)
| .[^'\''"/?\r\n]* # anything else
}{$+{comment} eq "" ? "" : sprintf("%5d %s\n", $l, $+{comment})}exsg'
在同一个样本上给出:
5 /* comment */
6 /\
* comment */
9 /* multiline
comment */
11 // comment
12 /\
/ comment
14 // multiline\
comment
17 /* comment */
18 /* comment */
21 /* comment */
26 /* "comment" */
答案3
可以按awk
如下方式完成:
#!/bin/awk
# Handles case where both /* and */ are on the same line
{ line_printed = 0; }
# Find the beginning of a multiline comment
/^[[:space:]]*\/\*/ {
multiline = 1;
# Remove leading spaces
sub(/^[[:space:]]+/,"");
printf "[%d] %s\n", NR, $0;
line_printed = 1;
}
# Find the end of a multiline comment
/\*\/[[:space:]]*$/ {
multiline = 0;
if (line_printed == 0)
printf "%s", $0;
print "\n"
next;
}
# The content between /* and */
{
if ( multiline == 1 && line_printed == 0 )
{
print $0;
next
}
}
# A single line comment
/^[[:space:]]*\/\// {
# Remove leading spaces
sub(/^[[:space:]]+/,"");
printf "[%d] %s\n\n", NR, $0;
}
将此脚本保存为foo.awk
(或任何其他名称;扩展名是可选的),然后使用awk -f foo.awk input.c
.该脚本将打印所有注释(由额外的换行符分隔),并在每个注释之前添加行号。
答案4
更新 2/15/24 - 在学习使用 Raylib 时,我遇到了他们的软件套件中包含的 C“解析器”,它似乎完全符合我的需要,请参阅:https://github.com/raysan5/raylib它还有一个额外的好处,可以查找并很好地格式化所有结构、定义、函数、回调等。
典型例子
Function 232: DrawRectangleRounded() (4 input parameters)
Name: DrawRectangleRounded
Return type: void
Description: Draw rectangle with rounded edges
Param[1]: rec (type: Rectangle)
Param[2]: roundness (type: float)
Param[3]: segments (type: int)
Param[4]: color (type: Color)