Eu estou executando um código que lê arquivos, faz algumas análises, mas precisa ignorar todos os comentários. Há boas explicações sobre como conduzi-lo, como a resposta para Como posso retirar comentários C de múltiplas linhas de um arquivo usando Perl?
$/ = undef;
$_ = <>;
s#/*[^*]**+([^/*][^*]**+)*/|("(\.|[^"\])*"|"(\.|[^"\])*"|.[^/""\]*)#defined $2 ? $2 : ""#gse;
print;
Meu primeiro problema é que depois de executar esta linha $/ = undef;
meu código não funciona corretamente. Na verdade, eu não sei o que isso faz. Mas se eu pudesse voltar atrás depois de ignorar todos os comentários, será útil.
Em geral, qual é a maneira útil de ignorar todos os comentários sem alterar o restante do código?
Respostas:
1 para resposta № 1Você quer fazer $/
local, como em
$_ = do { local $/; <> };
ou
{
local $/;
$_ = <>;
#...
}
Como alternativa, você poderia usar Arquivo :: Slurp
2 para resposta № 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
o comando awk define o separador de registro RS
para */
, que é a tag final para o comentário no estilo multilinha. então itera os registros, checando /*
, a tag de abertura, e então pegue o que estiver na frente /*
. este conceito é simples e você não precisa criar um regex complicado para isso. Similar, se você fosse fazer com o 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 para resposta № 3
Se você estiver removendo comentários "aninhados", por exemplo:
/* This is a comment
/* that has been re-commented */ possibly /* due to */
various modifications */
regexp pode não ser a melhor solução. Especialmente se isso envolver várias linhas, como no exemplo acima.
A última vez que eu tive que fazer algo assim, eu lias linhas uma de cada vez, mantendo uma contagem de quantos níveis de "/ *" (ou qualquer que fosse o delimitador para o idioma específico) e não imprimindo nada a menos que a contagem estivesse em 0.
Aqui está um exemplo - peço desculpas antecipadamente porque é muito ruim Perl, mas isso deve lhe dar uma idéia, pelo menos:
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: $!";