如何从C源文件中删除所有/ * * /注释?

我有一个C文件,我从别的地方复制,但它有很多像下面的评论:

int matrix[20]; /* generate data */ for (index = 0 ;index < 20; index++) matrix[index] = index + 1; /* print original data */ for (index = 0; index < 5 ;index++) 

如何删除/**/包含的所有注释。 有时,评论是由4-5行,我需要删除所有这些行。

基本上,我需要删除/**/之间的所有文本,甚至可以在\n之间插入。 请帮助我使用sedawkperl之一来执行此操作。

为什么不使用c预处理器来做到这一点? 你为什么只限于一个本土的正则表达式呢?

[编辑]这种方法也干净地处理Barts printf(".../*...")场景

例:

 [File: tc] /* This is a comment */ int main () { /* * This * is * a * multiline * comment */ int f = 42; /* * More comments */ return 0; } 

 $ cpp -P tc int main () { int f = 42; return 0; } 

或者你可以删除空白并压缩一切

 $ cpp -P tc | egrep -v "^[ \t]*$" int main () { int f = 42; return 0; } 

没有必要重新发明轮子,是吗?

[编辑]如果你不想通过这种方式来扩展包含的文件和宏, cpp提供了这个标志。 考虑:

[File:tc]

 #include <stdio.h> int main () { int f = 42; printf(" /* "); printf(" */ "); return 0; } 

 $ cpp -P -fpreprocessed tc | grep -v "^[ \t]*$" #include <stdio.h> int main () { int f = 42; printf(" /* "); printf(" */ "); return 0; } 

有一点需要注意,宏观扩张是可以避免的,但宏观的原始定义是从源头上剥离的。

参见perlfaq6 。 这是相当复杂的情况。

 $/ = undef; $_ = <>; s#/\*[^*]*\*+([^/*][^*]*\*+)*/|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)#defined $2 ? $2 : ""#gse; print; 

一个警告 – 一旦你这样做了,你有一个测试场景来证明你刚刚删除了评论,没有什么价值? 如果你正在运行如此强大的正则表达式,我会确保某种测试(即使你之前/之后只记录行为)。

看看Inline :: Filters中的strip_comments例程 :

 sub strip_comments { my ($txt, $opn, $cls, @quotes) = @_; my $i = -1; while (++$i < length $txt) { my $closer; if (grep {my $r=substr($txt,$i,length($_)) eq $_; $closer=$_ if $r; $r} @quotes) { $i = skip_quoted($txt, $i, $closer); next; } if (substr($txt, $i, length($opn)) eq $opn) { my $e = index($txt, $cls, $i) + length($cls); substr($txt, $i, $e-$i) =~ s/[^\n]/ /g; $i--; next; } } return $txt; } 

除非你明白这些后果,否则请不要使用cpp

 $ cat tc #include <stdio.h> #define MSG "Hello World" int main(void) { /* ANNOY: print MSG using the puts function */ puts(MSG); return 0; } 

现在,让我们通过cpp运行它:

 $ cpp -P tc -fpreprocessed #include <stdio.h> int main(void) { puts(MSG); return 0; } 

显然,这个文件不再是要编译的。

考虑:

 printf("... /* ..."); int matrix[20]; printf("... */ ..."); 

换句话说:我不会使用正则表达式来完成这个任务,除非你正在进行一次替换 ,并且肯定不会发生上述情况。

您必须使用C预处理程序与其他工具组合临时禁用特定的预处理程序功能(如扩展#defines或#include),所有其他方法在边缘情况下都将失败。 这将适用于所有情况:

 [ $# -eq 2 ] && arg="$1" || arg="" eval file="\$$#" sed 's/a/aA/g;s/__/aB/g;s/#/aC/g' "$file" | gcc -P -E $arg - | sed 's/aC/#/g;s/aB/__/g;s/aA/a/g' 

把它放在一个shell脚本中,并用你想要解析的文件的名字来调用它,或者用一个像“-ansi”这样的标志作为前缀来指定要应用的C标准。

在命令行上试试这个(用需要处理的文件列表替换“文件名”):

 perl -i -wpe 'BEGIN{undef $/} s!/\*.*?\*/!!sg' file-names 

该程序就地更改文件(用改正的输出覆盖原始文件)。 如果您只是想要输出而不更改原始文件,则省略“-i”开关。

说明:

 perl -- call the perl interpreter -i switch to 'change-in-place' mode. -w print warnings to STDOUT (if there are any) p read the files and print $_ for each record; like while(<>){ ...; print $_;} e process the following argument as a program (once for each input record) BEGIN{undef $/} --- process whole files instead of individual lines. s! search and replace ... /\* the starting /* marker .*? followed by any text (not gredy search) \*/ followed by the */ marker !! replace by the empty string (ie remove comments) s treat newline characters \n like normal characters (remove multi-line comments) g repeat as necessary to process all comments. file-names list of files to be processed. 

当我想要简短的CSS的东西,我使用这个:

 awk -vRS='*/' '{gsub(/\/\*.*/,"")}1' FILE 

这不会处理注释分隔符出现在字符串内的情况,但它比解决方案要简单得多。 显然,这不是防弹的,也不适合所有的事情,但是你比谁更了解你是否可以忍受。

我相信这个 防弹的。

尝试使用下面的递归方式查找和删除Java脚本类型注释,XML类型注释和单行注释

 /* This is a multi line js comments. Please remove me*/ 

for f in find pages/ -name "*.*" ; 做perl -i-wpe'BEGIN {undef $ /} s!/*.*?* / !! sg'$ f; DONE

 <!-- This is a multi line xml comments. Please remove me --> 

for f in find pages/ -name "*.*" ; 做perl -i-wpe'BEGIN {undef $ /} s!<! – 。*? – > !! sg'$ f; DONE

 //This is single line comment Please remove me. 

for f in find pages/ -name "*.*" ; 做sed -i的///.*//'$ f; DONE

注意:页面是一个根目录,上面的脚本也会在位于根目录和子目录的所有文件中查找和删除。

非常简单的使用gawk的例子。 在实施之前请测试很多次。 当然,它不会照顾其他评论风格//(在C ++中)

 $ more file int matrix[20]; /* generate data */ for (index = 0 ;index < 20; index++) matrix[index] = index + 1; /* print original data */ for (index = 0; index < 5 ;index++) /* function(){ blah blah } */ float a; float b; $ awk -vRS='*/' '{ gsub(/\/\*.*/,"")}1' file int matrix[20]; for (index = 0 ;index < 20; index++) matrix[index] = index + 1; for (index = 0; index < 5 ;index++) float a; float b;