Как можно игнорировать комментарии C, когда я обрабатываю исходный файл C с помощью Perl? - PullRequest
1 голос
/ 14 апреля 2010

Я запускаю код, который читает файлы, выполняет некоторый анализ, но должен игнорировать все комментарии. Есть хорошие объяснения, как это сделать, например, ответ на Как я могу удалить многострочные комментарии C из файла, используя Perl?

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

Моя первая проблема - после запуска этой строки $/ = undef; мой код не работает должным образом. На самом деле, я не знаю, что он делает. Но если бы я мог повернуть его обратно после игнорирования всех комментариев, это будет полезно.

В общем, каков полезный способ игнорировать все комментарии без изменения остальной части кода?

Ответы [ 3 ]

2 голосов
/ 14 апреля 2010

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 голос
/ 14 апреля 2010

Вы хотите сделать $/ локальным, как в

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

или

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

В качестве альтернативы, вы можете использовать File :: Slurp

1 голос
/ 14 апреля 2010

Если вы удаляете «вложенные» комментарии, то есть ::1001*

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

регулярное выражение может быть не лучшим решением. Особенно, если это занимает несколько строк, как в примере выше.

В прошлый раз, когда мне приходилось делать что-то подобное, я читал строки по одной, сохраняя счет количества уровней «/ *» (или любого другого разделителя для конкретного языка) и ничего не печатая, счет был в 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: $!";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...