2009-11-11 26 views
13

tengo un archivo de C, que he copiado de otro lugar, pero tiene un montón de comentarios como a continuación:¿Cómo puedo eliminar todos/* */comentarios de un archivo fuente en 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++) 

¿Cómo puedo eliminar todos los comentarios cerrados por /* y */. A veces, los comentarios consisten en 4-5 líneas, y necesito eliminar todas esas líneas.

Básicamente, tengo que eliminar todo el texto entre /* y */ e incluso \n pueden entrar en el medio. Por favor, ayúdenme a hacer esto usando uno de sed, awk o perl.

+11

Me encanta la palabra "pero" en "Tengo un archivo de C, pero tiene un montón de comentarios". – innaM

+0

@Manni ;-) ver http://stackoverflow.com/questions/1260273/am-i-being-unreasonable-in-rejecting-candidates-with-poor-spelling-and-grammar/1260285#1260285 –

+3

Sin duda, algunos comentarios son una locura ¿Pero deshacerse de ** todos * los comentarios? – innaM

Respuesta

31

¿Por qué no usar el preprocesador c para hacer esto? ¿Por qué te estás limitando a un regex casero?

[Editar] Este enfoque también se ocupa de Barts printf(".../*...") escenario limpiamente

Ejemplo:

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

O puede eliminar el espacio y condensar todo lo

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

Ningún uso de reinventar la rueda, ¿verdad?

[Editar] Si desea no archivos y macroa ampliar incluidos por este enfoque, cpp proporciona banderas para esto. Considere:

[Archivo: 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; 
} 

Hay es una ligera advertencia en que la expansión macro se puede evitar, pero la definición original de la macro es despojado de la fuente.

+1

Sí, esto es lo que usaría! –

+4

El preprocesador tiene una (potencialmente indésirable) "efecto secundario": que también procesa las macros, incluye archivos incluidos, y así sucesivamente ... –

+4

Usted puede deshacerse de la expansión de la macro por '-fpreprocessed'. Actualizaré para mencionar nuevamente – ezpz

12

Ver perlfaq6. Es un escenario bastante complejo.

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

Una palabra de advertencia - una vez que haya hecho esto, ¿Tiene un escenario de prueba para demostrar a sí mismo que ha acaba de quitar los comentarios y nada de valor? Si está ejecutando una expresión regular tan potente, me aseguraría de realizar algún tipo de prueba (incluso si simplemente registra el comportamiento antes/después).

+0

Simplemente compruebe que los binarios creados mediante la compilación sean idénticos (marcas de tiempo modulo u otra identificación de compilación). – ephemient

+0

Esa puede ser la solución más simple –

+1

De acuerdo, nunca haría esto en el código que me importaba a menos que tuviera pruebas unitarias para verificar su corrección después de filtrarlo. – Ether

0

ejemplo muy simplista usando gawk. Por favor, prueba muchas veces antes de implementar. Por supuesto que no se ocupa de otro estilo de comentario // (en 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; 
+0

por alguna razón esto no funciona en mi máquina :( 'cat prueba int matriz [20]; /* generar datos */ para (index = 0; index <20; índice ++) matriz [index] = índice + 1; /* imprimir datos originales */' y la salida es ' awk -vRS = '* /' '{gsub (/\/\*.*/, "")} 1' prueba int matriz [20]; / generar datos / para (index = 0; index <20; índice ++) matriz [index] = índice + 1; / impresión de datos originales / ' – Vijay

+0

ya lo indiqué, usando gawk. ¿tienes boquiabierto? – ghostdog74

+0

lo siento, el comentario está muy desordenado, no noté que tenías salida. Bueno, funcionó para mí. Veo que todavía tiene/genera datos/y/imprime datos originales /. Como puede ver en mi salida, me funciona. – ghostdog74

2

Pruebe esto en la línea de comandos (en sustitución de 'nombres de archivos' con la lista de archivos que necesitan ser procesado):

perl -i -wpe 'BEGIN{undef $/} s!/\*.*?\*/!!sg' file-names 

Este programa cambia los archivos in situ (sobrescribiendo el archivo original con la salida corregida). Si solo quiere la salida sin cambiar los archivos originales, omita el modificador '-i'.

Explicación:

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. 
+0

Consulte el perlfaq para comprender por qué esto es tan incorrecto. –

+0

@brian Aceptado: esta es solo una solución aproximada. –

6

Tome un vistazo a la 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; 
} 
4

considerar:

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

En otras palabras: Yo no usaría la expresión regular para este tarea, a menos que esté haciendo una copia ace-once y es positivo que lo anterior no ocurra.

5

Por favor, no use cpp para este a menos que entienda las ramificaciones:

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

#define MSG "Hello World" 

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

Ahora, vamos a ejecutar a través de cpp:

$ cpp -P t.c -fpreprocessed 


#include <stdio.h> 



int main(void) { 


    puts(MSG); 
    return 0; 
} 

Claramente, este archivo ya no se va a compilar.

+0

bien, no después de agregar el indicador '-fpreprocessed', de todos modos – Hasturkun

+0

@Hasturkun y si no agrega -fpreprocessed,' #include 'se expandirá . –

+0

yo probamos este: Perl -wpe 's/^ \ S * # define/# include # define /' tu-file.c | CPP -P - -fpreprocessed | Perl -wpe 's/# incluyen #define/# include/---- esto convierte #defines en (algo inválido) #includes que pasan a través del preprocesador, para ser convertidos de nuevo a #defines correctos más tarde. –

1

Cuando quiero algo corto y sencillo para CSS, yo uso esto:

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

Esto no va a manejar el caso en el que aparecen los delimitadores de comentarios cuerdas dentro, pero es mucho más simple que una solución que hace. Obviamente no es a prueba de balas o adecuado para todo, pero usted sabe mejor que los pedantes en SO, ya sea que pueda vivir con eso o no.

Creo this onees a prueba de balas sin embargo.

3

DEBE usar un preprocesador C para esto en combinación con otras herramientas para deshabilitar temporalmente la funcionalidad del preprocesador específico, como expandir #defines o #includes, todos los demás enfoques fallarán en casos extremos. Esto funcionará para todos los casos:

[ $# -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' 

Póngalo en un shell script y llamarlo con el nombre del archivo que desea analizado, opcionalmente precedido de una bandera como "-ansi" para especificar el nivel C de aplicar .

+1

¿por qué esta no es la respuesta más votada? – Sam

+1

Sospecho que porque otras soluciones publicadas parecen más simples, pero mientras ésta funcionará TODO el tiempo, las demás solo funcionarán ALGUNAS veces y cualquiera que las intente todavía no ha llegado a aquellos casos en los que falla su elección de solución (o hasn ' noté la falla).¡Ah, parece que publiqué esto 3 años después de que se publicara la pregunta original y se aceptara una respuesta, por lo que probablemente sea un factor importante! –

+1

Recuerdo haber hecho algo como esto hace mucho tiempo. Lo necesitaba de nuevo por algo rápido ayer y sabía que las otras respuestas no cubrirían todos los casos. ¡Ojalá pudiera volver a votarlo de nuevo! – Sam

1

Pruebe la forma recursiva a continuación de la búsqueda y eliminación de Java comentarios script type, tipo XML y comentarios de una sola línea comenta

/* This is a multi line js comments. 

Please remove me*/ 

para f en find pages/ -name "*.*"; do perl -i -wpe 'BEGIN {undef $ /} s! /*.*? */!! sg' $ f; hecho

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

Please remove me --> 

para f en find pages/ -name "*.*"; do perl -i -wpe 'BEGIN {undef $ /} s! <! -. *? -> !!sg '$ f; hecho

//This is single line comment Please remove me. 

para f en find pages/ -name "*.*"; do sed -i ///.*// '$ f;

hecho

Nota: Las páginas es un directorio raíz y el script anterior en encontrar y eliminar todos los archivos que se encuentran en la raíz y sub directorios también.

Cuestiones relacionadas