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

时间:2009-11-11 11:15:25

标签: regex perl unix sed awk

我有一个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之一帮助我这样做。

10 个答案:

答案 0 :(得分:31)

为什么不使用c预处理器来执行此操作?你为什么要把自己限制在一个本土的正则表达式?

[编辑]此方法还可以干净地处理Barts printf(".../*...")场景

示例:

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

$ cpp -P t.c
int main () {







    int f = 42;



    return 0;
}

或者您可以删除空白并压缩所有内容

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

没有用再重新发明轮子,是吗?

[编辑] 如果您希望通过此方法扩展包含的文件和macroa,cpp会为此提供标记。考虑:

[档案:t.c]

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

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

有一点需要注意,可以避免宏扩展,但宏的原始定义会从源中删除。

答案 1 :(得分:12)

perlfaq6。这是一个非常复杂的场景。

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

警告 - 一旦你完成了这项工作,你是否有一个测试场景向自己证明你刚刚删除了评论而没有任何价值?如果你正在运行如此强大的正则表达式,我会确保进行某种测试(即使你只是记录之前/之后的行为)。

答案 2 :(得分:6)

查看strip_comments routine in Inline::Filters

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;
}

答案 3 :(得分:5)

除非您了解其后果,否则请不要使用cpp

$ cat t.c
#include <stdio.h>

#define MSG "Hello World"

int main(void) {
    /* ANNOY: print MSG using the puts function */
    puts(MSG);
    return 0;
}

现在,让我们通过cpp

运行它
$ cpp -P t.c -fpreprocessed


#include <stdio.h>



int main(void) {


    puts(MSG);
    return 0;
}

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

答案 4 :(得分:4)

考虑:

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

换句话说:我不会使用正则表达式执行此任务,除非您正在执行 replace-once 并且肯定上述情况不会发生。

答案 5 :(得分:3)

您必须将C预处理器与其他工具结合使用,以暂时禁用特定的预处理器功能,例如扩展#defines或#includes,所有其他方法在边缘情况下都会失败。这适用于所有情况:

[ $# -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标准。

答案 6 :(得分:2)

在命令行上尝试此操作(将'file-names'替换为需要处理的文件列表):

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 (i.e. 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.

答案 7 :(得分:1)

当我想要简短而简单的CSS时,我会使用它:

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

这不会处理注释分隔符出现在字符串中的情况,但它比解决方案简单得多。显然它不是防弹或适合所有的东西,但是你知道你是否可以忍受这种情况,而不管你是否能够忍受。

我相信this one 是防弹的。

答案 8 :(得分:1)

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

/* This is a multi line js comments.

Please remove me*/

表示find pages/ -name "*.*"中的f;做perl -i -wpe&#39; BEGIN {undef $ /} s!/ *。*?* / !! sg&#39; $ F;完成

<!-- This is a multi line xml comments.

Please remove me -->

表示find pages/ -name "*.*"中的f;做perl -i -wpe&#39; BEGIN {undef $ /} s!&lt;! - 。*? - &gt; !! sg&#39; $ F;完成

//This is single line comment Please remove me.

表示find pages/ -name "*.*"中的f;做sed -i&#39; s ///.*//' $ F;完成

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

答案 9 :(得分:0)

使用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;