2009-11-11 14 views
13

Mam plik C którego skopiowany z innego miejsca, ale ma wiele uwag jak poniżej:Jak mogę usunąć wszystkie/* */komentarze z pliku źródłowego 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++) 

Jak mogę usunąć wszystkie komentarze zamknięte przez /* i */. Czasami komentarze składają się z 4-5 linii i muszę usunąć wszystkie te linie.

Zasadniczo muszę usunąć cały tekst między /* i */, a nawet \n może wejść pomiędzy. Pomóż mi to zrobić, używając jednego z sed, awk lub perl.

+11

Uwielbiam słowo "ale" w "Mam plik C, ale ma wiele komentarzy". – innaM

+0

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

+3

Bez wątpienia, niektóre komentarze są szalone. Ale pozbycie się ** wszystkich * komentarzy? – innaM

Odpowiedz

31

Dlaczego po prostu nie użyć preprocesora c, aby to zrobić? Dlaczego ograniczasz się do rodzimego regexu?

[Edycja] To podejście prowadzi również barts printf(".../*...") scenariusz czysto

przykład:

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

Albo można usunąć spacje i skondensować wszystko

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

bezużyteczna ponowne wynalezienie koła, tam jest?

[Edytuj] Jeśli chcesz nie poszerzyć dołączonych plików i macroa przez tego podejścia cpp zapewnia flagi do tego. Rozważmy:

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

nie jest można uniknąć niewielkie zastrzeżenie w tym makr, ale przy definicji makro jest usuwany ze źródła.

+1

Tak, właśnie tego używam! –

+4

Preprocesor ma (potencjalnie niepożądany) "efekt uboczny": przetwarza również makra, zawiera dołączone pliki itd. –

+4

Możesz pozbyć się rozszerzenia makro przez "-fpreprocessed". Zaktualizuję, aby ponownie wspomnieć o tej – ezpz

12

Zobacz perlfaq6. To dość skomplikowany scenariusz.

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

Słowo ostrzeżenia - raz już to zrobisz, masz scenariusz testowy, aby udowodnić sobie, że właśnie usunięte komentarze i nic wartościowego? Jeśli używasz tak potężnego wyrażenia regularnego, zapewniłbym pewien test (nawet jeśli po prostu nagrasz zachowanie przed/po).

+0

Sprawdź tylko, czy pliki binarne utworzone przez kompilowanie są identyczne (modulo timestamps lub inne identyfikatory kompilacji). – ephemient

+0

To może być najprostsze rozwiązanie. –

+1

Zgadzam się, nigdy bym tego nie zrobił na kodzie, o który dbałem, chyba że miałem testy jednostkowe w celu sprawdzenia poprawności po przefiltrowaniu. – Ether

0

bardzo uproszczony przykład użycia gawk. Proszę przetestować wiele razy przed wdrożeniem. Oczywiście nie dbać o innych uwag stylu // (w 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

z jakiegoś powodu nie działa w moim maszyny :( też cat Test Int macierzy [20] /* generowania danych */ do (wskaźnik = 0; wskaźnik <20; wskaźnik ++) macierzy [indeks] = index + 1; /* wydrukuj oryginalne dane */' , a wynikiem jest ' awk -vRS = '* /' '{gsub (/\/\*.*/, "")} 1' test int matrycowe [20]; / generowania danych / dla (wskaźnik = 0; wskaźnik <20; wskaźnik ++) matryca [indeks] = wskaźnik + 1; / druku oryginalne dane / ' – Vijay

+0

już wskazałem, używając gawk. masz gawk? – ghostdog74

+0

Przepraszam, komentarz jest tak pomieszany, nie zauważyłem, że masz wyjście. Cóż, zadziałało to dla mnie. Widzę, że nadal masz/generujesz dane/i/drukuj oryginalne dane /. Jak widać z moich wyników, to działa dla mnie. – ghostdog74

2

Spróbuj to w wierszu poleceń (zastępując „file-nazwy” z listą plików, które muszą być przetworzone):

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

Ten program zmienia pliki w miejscu (zastępując oryginalny plik poprawionymi danymi wyjściowymi). Jeśli chcesz tylko dane wyjściowe bez zmiany oryginalnych plików, pomiń przełącznik "-i".

Objaśnienie:

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

Zobacz perlfaq, aby zrozumieć, dlaczego tak jest bardzo źle. –

+0

@brian Accepted: To jest tylko przybliżone rozwiązanie. –

6

Spójrz na 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

Rozważmy:

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

Innymi słowy: nie będę używać tego wyrażenia regularnego zadanie, chyba że robisz replikę ace-once i są pozytywne, że powyższe nie występuje.

5

Proszę nie używać cpp za to chyba rozumiesz konsekwencje:

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

#define MSG "Hello World" 

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

Teraz niech go uruchomić poprzez cpp:

$ cpp -P t.c -fpreprocessed 


#include <stdio.h> 



int main(void) { 


    puts(MSG); 
    return 0; 
} 

Oczywiście, ten plik nie jest już zamiar skompilować.

+0

cóż, nie po dodaniu flagi '-fpreprocessed', w każdym razie – Hasturkun

+0

@Hasturkun i jeśli nie dodasz -fpreprocessed,' #include 'zostanie rozszerzone . –

+0

Próbowałem to: perl -wpe 's/^ \ s * # define/# include # define /' your-file.c | cpp -P - -fpreprocessed | perl -wpe 's/# include # define/# include/---- to zmienia dowolne #defines na (nieco niepoprawne) # obejmuje te, które przechodzą przez preprocesor, aby zostać przekonwertowane z powrotem na poprawne #defines później. –

1

Gdy chcę coś krótkie i proste dla CSS, używam to:

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

To nie zajmie się przypadek, w którym komentarz ograniczniki pojawić wewnątrz sznurki, ale jest to znacznie prostsze niż rozwiązanie, które robi. Oczywiście nie jest to kuloodporna lub nadaje się do wszystkiego, ale wiesz lepiej niż pedanci na SO, czy możesz z tym żyć.

Wierzę, this onejest kuloodporna jednak.

3

MUSISZ używać preprocesora C do tego w połączeniu z innymi narzędziami do tymczasowego wyłączenia określonych funkcji preprocesora, takich jak rozszerzanie #defines lub #includes, wszystkie inne podejścia będą nieskuteczne w przypadkach krawędzi. To będzie działać we wszystkich przypadkach:

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

Umieścić go w skrypcie powłoki i wywołać ją z nazwą pliku, który ma zostać przetworzony, ewentualnie poprzedzony flagą jak „-ansi”, aby określić standard C do zastosowania .

+1

dlaczego ta odpowiedź nie jest najbardziej odpowiednia? – Sam

+1

Podejrzewam, że inne opublikowane rozwiązania wyglądają na prostsze, ale podczas gdy ten będzie działał CAŁY czas, inne będą działały NIEKTÓRE czasu i każdy, kto go wypróbuje, jeszcze nie trafił w te przypadki, w których ich wybór rozwiązania się nie udał (lub t zauważyłem awarię).Wygląda na to, że opublikowałem to 3 lata po opublikowaniu pierwotnego pytania, a odpowiedź została zaakceptowana, więc prawdopodobnie jest to istotny czynnik! –

+1

Pamiętam, że robiłem coś takiego dawno temu. Potrzebowałem go jeszcze raz na coś wczorajszego i wiedziałem, że inne odpowiedzi nie obejmą wszystkich przypadków. Chciałbym móc jeszcze raz zagłosować! – Sam

1

Spróbuj poniżej rekurencyjny sposób znajdowania i usuwania komentarzy Java script type, typ XML Komentarze i jeden wiersz komentarze

/* This is a multi line js comments. 

Please remove me*/ 

dla F w find pages/ -name "*.*"; do perl -i -wpe 'BEGIN {undef $ /} s! /*.*? */!! sg' $ f; wykonano:

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

Please remove me --> 

dla fw find pages/ -name "*.*"; do perl -i -wpe 'BEGIN {undef $ /} s! <! -. *? -> !!sg '$ f; wykonano:

//This is single line comment Please remove me. 

dla fw find pages/ -name "*.*"; do sed -i 's ///.*//' $ f; Sporządzono:

Uwaga: strony są katalogiem głównym, a powyższy skrypt znajdzie i usunie wszystkie pliki znajdujące się w katalogach głównym i podrzędnym.

Powiązane problemy