当我使用Perl处理C源文件时,如何忽略C注释?

时间:2010-04-14 08:01:06

标签: perl

我正在运行一个读取文件的代码,进行一些解析,但需要忽略所有注释。 有很好的解释如何进行,如How can I strip multiline C comments from a file using Perl?

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

我的第一个问题是,在运行此行$/ = undef;后,我的代码无法正常运行。 实际上,我不知道它做了什么。但是,如果我在忽略所有评论后将其转回,那将会有所帮助。

一般情况下,在不更改其余代码的情况下忽略所有注释的有用方法是什么?

3 个答案:

答案 0 :(得分:2)

AWK

$ cat file.c
one
two
three // comment at the back
// comment in front
four /* another comment */
/* comment spanning
   multiple
   lines
*/  five
six
seven

$ awk -vRS='*/' '{ gsub(/\/\*.*/,"");gsub("//.*","")}1' file.c
one
two
three


  five
six
seven

awk命令将记录分隔符RS设置为*/,这是多行样式注释的结束标记。所以它迭代记录,检查/*,开始标记,然后得到/*前面的任何内容。这个概念很简单,你不必为此制作复杂的正则表达式。类似的,如果你是用Python做的,

>>> data=open("file").read() 
>>> for item in data.split("*/"):
...     if "//" in item: item=item.split("//")[0]
...     if "/*" in item: item=item.split("/*")[0]
...     print item
...
one
two
three


  five
six
seven

答案 1 :(得分:1)

如果要剥离“嵌套”注释,即:

/* This is a comment 
/* that has been re-commented */ possibly /* due to */ 
various modifications */

regexp可能不是最佳解决方案。特别是如果这跨越多行,如上例所示。

上次我不得不做这样的事情,我一次读一行,记录多少级别的“/ *”(或者特定语言的分隔符)并且不打印任何内容伯爵是0。

这是一个例子 - 我提前道歉,因为Perl非常糟糕,但这应该给你一个想法,至少:

use strict;

my $infile = $ARGV[0]; # File name

# Slurp up input file in an array
open (FH, "< $infile")  or die "Opening: $infile";
my @INPUT_ARRAY = <FH>;
my @ARRAY;
my ($i,$j);
my $line;


# Removes all kind of comments (single-line, multi-line, nested).
# Further parsing will be carried on the stripped lines (in @ARRAY) but
# the error messaging routine will reference the original @INPUT_ARRAY
# so line fragments may contain comments.
my $commentLevel = 0;

for ($i=0; $i < @INPUT_ARRAY; $i++)
{
    my @explodedLine = split(//,$INPUT_ARRAY[$i]);
    my $resultLine ="";

    for ($j=0; $j < @explodedLine; $j++)
    {
        if ($commentLevel > 0)
        {
            $resultLine .= " ";
        }
        if ($explodedLine[$j] eq "/" && $explodedLine[($j+1)] eq "*")
        {
                $commentLevel++;
                next;
        }           
        if ($explodedLine[$j] eq "*" && $explodedLine[($j+1)] eq "/")
        {
                $commentLevel--;
                $j++;
                next;
        }       
        if (($commentLevel == 0) || ($explodedLine[$j] eq "\n"))
        {
            $resultLine .= $explodedLine[$j];
        }
    }

 $ARRAY[$i]=join(" ",$resultLine);  
}   


close(FH)   or die "Closing: $!";

答案 2 :(得分:1)

您希望将$/设为本地,如

$_ = do { local $/; <> };

{
    local $/;
    $_ = <>;
    #...
}

或者,您可以使用File::Slurp