Como posso apagar todos os caracteres que se encaixam em / *… * / incluindo / * & * /?

12

Eu tentei sed e awk, mas não funciona como o caractere envolve "/" que já está lá no comando como delimitador.

Por favor, deixe-me saber como posso conseguir isso.

Abaixo está uma amostra Exemplo. Desejamos remover as seções comentadas, por exemplo, /*.....*/

/*This is to print the output
data*/
proc print data=sashelp.cars;
run;
/*Creating dataset*/
data abc;
set xyz;
run;
    
por Sharique Alam 21.07.2016 / 12:53

7 respostas

21

Acho que encontrei uma solução fácil!

cpp -P yourcommentedfile.txt 

ALGUMAS ATUALIZAÇÕES:

Citação do usuário ilkachu (texto original dos comentários do usuário):

Eu joguei um pouco com as opções do gcc: -fpreprocessed desabilitará a maioria das diretivas e expansões de macro (exceto #define e #undef aparentemente). Adicionando -dD deixará define em também; e std = c89 pode ser usado para ignorar novos estilos // comentários. Mesmo com eles, o cpp substitui os comentários por espaços (em vez de removê-los) e recolhe espaços e linhas vazias.

Mas eu acho que ainda é razoável e uma solução fácil para a maioria dos casos, se você desabilitar a expansão de macro e outras coisas eu acho que você obterá bons resultados ... - e sim você pode combinar isso com shell script para ficar melhor ... e muito mais ...

    
por 21.07.2016 / 15:10
10

Uma vez eu criei este que podemos refinar:

perl -0777 -pe '
  BEGIN{
    $bs=qr{(?:\|\?\?/)};
    $lc=qr{(?:$bs\n|$bs\r\n?)}
  }
  s{
    /$lc*\*.*?\*$lc*/
    | /$lc*/(?:$lc|[^\r\n])*
    | (
         "(?:$bs$lc*.|.)*?"
       | '\''$lc*(?:$bs$lc*(?:\?\?.|.))?(?:\?\?.|.)*?'\''
       | \?\?'\''
       | .[^'\''"/?]*
      )
  }{$1 eq "" ? " " : "$1"}exsg'

para lidar com mais alguns casos importantes.

Se você remover um comentário, poderá alterar o significado do código ( 1-/* comment */-1 é analisado como 1 - -1 enquanto 1--1 (o que você obteria se removesse o comentário) lhe daria um erro). É melhor substituir o comentário por um caractere de espaço (como fazemos aqui) em vez de removê-lo completamente.

O acima deve funcionar corretamente neste código ANSI C válido, por exemplo, que tenta incluir alguns casos:

#include <stdio.h>
int main()
{
  printf("%d %s %c%c%c%c%c %s %s %d\n",
  1-/* comment */-1,
  /\
* comment */
  "/* not a comment */",
  /* multiline
  comment */
  '"' /* comment */ , '"',
  '\'','"'/* comment */,
  '\
\
"', /* comment */
  "\
" /* not a comment */ ",
  "??/" /* not a comment */ ",
  '??''+'"' /* "comment" */);
  return 0;
}

O que dá esta saída:

#include <stdio.h>
int main()
{
  printf("%d %s %c%c%c%c%c %s %s %d\n",
  1- -1,

  "/* not a comment */",

  '"'   , '"',
  '\'','"' ,
  '\
\
"',  
  "\
" /* not a comment */ ",
  "??/" /* not a comment */ ",
  '??''+'"'  );
  return 0;
}

Ambos imprimem a mesma saída quando compilados e executados.

Você pode comparar com a saída de gcc -ansi -E para ver o que o pré-processador faria nele. Esse código também é válido para o código C99 ou C11, no entanto gcc desativa o suporte a trigraphs por padrão para não funcionar com gcc , a menos que você especifique o padrão como gcc -std=c99 ou gcc -std=c11 ou adicione a opção -trigraphs ) .

Também funciona neste código C99 / C11 (não-ANSI / C90):

// comment
/\
/ comment
// multiline\
comment
"// not a comment"

(compare com gcc -E / gcc -std=c99 -E / gcc -std=c11 -E )

ANSI C não suportou o // form de comentários. // não é válido de outra forma no ANSI C, portanto, não apareceria lá. Um caso planejado em que // pode realmente aparecer em ANSI C (conforme observado , e você pode achar interessante o resto da discussão) é quando o operador stringify está em uso.

Este é um código ANSI C válido:

#define s(x) #x
s(//not a comment)

E no momento da discussão em 2004, gcc -ansi -E de fato expandiu para "//not a comment" . No entanto, hoje em dia, gcc-5.4 retorna um erro, então duvido que encontremos muito código C usando esse tipo de construção.

O equivalente sed do GNU pode ser algo como:

lc='([\%]\n|[\%]\r\n?)'
sed -zE "
  s/_/_u/g;s/!/_b/g;s/</_l/g;s/>/_r/g;s/:/_c/g;s/;/_s/g;s/@/_a/g;s/%/_p/g;
  s@\?\?/@%@g;s@/$lc*\*@:&@g;s@\*$lc*/@;&@g
  s:/$lc*/:@&:g;s/\?\?'/!/g
  s#:/$lc*\*[^;]*;\*$lc*/|@/$lc*/$lc*|(\"([\\%]$lc*.|[^\\%\"])*\"|'$lc*([\\%]$lc*.)?[^\\%']*'|[^'\"@;:]+)#<>#g
  s/<>/ /g;s/!/??'/g;s@%@??/@g;s/[<>@:;]//g
  s/_p/%/g;s/_a/@/g;s/_s/;/g;s/_c/:/g;s/_r/>/g;s/_l/</g;s/_b/!/g;s/_u/_/g"

Se o seu GNU sed for muito antigo para suportar -E ou -z , você poderá substituir a primeira linha por:

sed -r ":1;\$!{N;b1}
    
por 21.07.2016 / 15:16
6

com sed :

UPDATE

/\/\*/ {
    /\*\// {
        s/\/\*.*\*\///g;
        b next
    };

    :loop;
    /\*\//! {
        N;
        b loop
    };
    /\*\// {
        s/\/\*.*\*\//\n/g
    }
    :next
}

suporta todos os possíveis (comentário de várias linhas, dados após [ou e] antes,);

 e1/*comment*/
-------------------
e1/*comment*/e2
-------------------
/*comment*/e2
-------------------
e1/*com
ment*/
-------------------
e1/*com
ment*/e2
-------------------
/*com
ment*/e2
-------------------
e1/*com
1
2
ment*/
-------------------
e1/*com
1
2
ment*/e2
-------------------
/*com
1
2
ment*/e2
-------------------
corre:
$ sed -f command.sed FILENAME

e1
-------------------
e1e2
-------------------
e2
-------------------
e1

-------------------
e1
e2
-------------------

e2
-------------------
e1

-------------------
e1
e2
-------------------

e2
-------------------
    
por 21.07.2016 / 14:28
4
 $ cat file | perl -pe 'BEGIN{$/=undef}s!/\*.+?\*/!!sg'

 proc print data=sashelp.cars;
 run;

 data abc;
 set xyz;
 run;

Remova as linhas em branco, se houver:

 $ cat file | perl -pe 'BEGIN{$/=undef}s!/\*.+?\*/\n?!!sg'

Editar - a versão mais curta de Stephane:

 $ cat file | perl -0777 -pe 's!/\*.*?\*/!!sg'
    
por 21.07.2016 / 14:06
2

Solução usando o comando SED e nenhum script

Aqui você está:

sed 's/\*\//\n&/g' test | sed '/\/\*/,/\*\//d'

N.B. Isso não funciona no OS X, a menos que você instale gnu-sed . Mas funciona no Linux Distros.

    
por 21.07.2016 / 13:36
1

sed opera em uma linha por vez, mas alguns dos comentários na entrada abrangem várias linhas. De acordo com o link , você pode usar primeiro tr para transformar as quebras de linha em outro caractere. Então, sed pode processar a entrada como uma única linha e você usa tr novamente para restaurar as quebras de linha.

tr '\n' '
tr '\n' '
data1 /* multiline
comment */ data2
' | sed -e 's,/\*\([^*]\|\*\+[^*/]\)*\*\+/,,g' | tr '
data1  data2
' '\n'
' | sed ... | tr '
tr '\n' '\f' | sed -e 's,/\*\(\(\f\)\|[^*]\|\*\+[^*/]\)*\*\+/,,g' | tr '\f' '\n'
' \n'

Eu usei null bytes, mas você pode escolher qualquer caractere que não apareça no seu arquivo de entrada.

* tem um significado especial em expressões regulares, portanto, será necessário escapar como \* para corresponder a um literal * .

.* é ganancioso - corresponderá ao texto mais longo possível, incluindo mais */ e %código%. Isso significa o primeiro comentário, o último comentário e tudo mais. Para restringir isso, substitua /* por um padrão mais estrito: os comentários podem conter qualquer coisa que não seja um "*" e também "*" seguido de qualquer coisa que não seja "/". Execuções de vários .* s também precisam ser contabilizadas:

tr '\n' '
tr '\n' '
data1 /* multiline
comment */ data2
' | sed -e 's,/\*\([^*]\|\*\+[^*/]\)*\*\+/,,g' | tr '
data1  data2
' '\n'
' | sed ... | tr '
tr '\n' '\f' | sed -e 's,/\*\(\(\f\)\|[^*]\|\*\+[^*/]\)*\*\+/,,g' | tr '\f' '\n'
' \n'

Isso removerá qualquer quebra de linha nos comentários de várias linhas, ou seja,

%pre%

se tornará

%pre%

Se este não for o desejado, * poderá ser informado para manter uma das quebras de linha. Isso significa escolher um caractere de substituição de quebra de linha que possa ser correspondido.

%pre%

O caractere especial sed e o uso de uma referência de retorno que pode não ter correspondido a nada não funcionam garantidamente como esperado em todas as implementações de \f . (Eu confirmei que funciona no GNU sed 4.07 e 4.2.2.)

    
por 21.07.2016 / 14:06
0

usando uma linha sed para remover comentários:

sed '/\/\*/d;/\*\//d' file

proc print data=sashelp.cars;
run;
data abc;
set xyz;
run;
    
por 19.01.2017 / 16:37