Как я могу удалить все / * * / комментарии из исходного файла C? - PullRequest
13 голосов
/ 11 ноября 2009

У меня есть файл 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++)

Как я могу удалить все комментарии, приложенные /* и */. Иногда комментарии состоят из 4-5 строк, и мне нужно удалить все эти строки.

По сути, мне нужно удалить весь текст между /* и */, и даже \n может быть между Пожалуйста, помогите мне сделать это, используя один из sed, awk или perl.

Ответы [ 10 ]

31 голосов
/ 11 ноября 2009

Почему бы просто не использовать препроцессор c для этого? Почему вы ограничиваетесь доморощенным регулярным выражением?

[Edit] Этот подход также корректно обрабатывает сценарий Бартса printf(".../*...")

Пример:

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

Или вы можете удалить пробел и сжать все

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

Нет смысла заново изобретать колесо?

[Изменить] Если вы хотите , а не расширять включенные файлы и макросы с помощью этого подхода, cpp предоставляет для этого флаги. Рассмотрим:

[Файл: 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;
}

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

12 голосов
/ 11 ноября 2009

См. perlfaq6 . Это довольно сложный сценарий.

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

Слово предупреждения - как только вы это сделаете, у вас есть тестовый сценарий, чтобы доказать себе, что вы только что удалили комментарии и ничего ценного? Если вы используете такое мощное регулярное выражение, я бы проверил какой-то тест (даже если вы просто запишите поведение до / после).

6 голосов
/ 11 ноября 2009

Взгляните на подпрограмму strip_comments в 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;
}
5 голосов
/ 11 ноября 2009

Пожалуйста, не используйте cpp для этого, если вы не понимаете последствия:

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

#define MSG "Hello World"

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

Теперь давайте пройдем через cpp:

$ cpp -P t.c -fpreprocessed


#include <stdio.h>



int main(void) {


    puts(MSG);
    return 0;
}

Очевидно, что этот файл больше не собирается компилироваться.

4 голосов
/ 11 ноября 2009

Рассмотрим:

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

Другими словами: я бы не использовал regex для этой задачи, если вы не выполняете replace-Once и не уверены, что вышеописанное не происходит.

3 голосов
/ 25 октября 2012

Вы ДОЛЖНЫ использовать препроцессор C для этого в сочетании с другими инструментами, чтобы временно отключить определенные функции препроцессора, такие как расширение #defines или #include, все остальные подходы в крайних случаях потерпят неудачу. Это будет работать для всех случаев:

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

Поместите его в сценарий оболочки и назовите его с именем файла, который вы хотите проанализировать, опционально с префиксом, например, "-ansi", чтобы указать применяемый стандарт C.

2 голосов
/ 11 ноября 2009

Попробуйте это в командной строке (заменив 'имена файлов' списком файлов, которые нужно обработать):

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

Эта программа изменяет файлы на месте (перезаписывает исходный файл с исправленным выводом). Если вы просто хотите вывод без изменения исходных файлов, опустите ключ '-i'.

Пояснение:

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.
1 голос
/ 22 сентября 2014

Попробуйте рекурсивный способ поиска и удаления комментариев типа скрипта Java, комментариев типа XML и однострочных комментариев ниже

/* This is a multi line js comments.

Please remove me*/

для f в find pages/ -name "*.*"; do perl -i -wpe 'BEGIN {undef $ /} s! /*.*? * / !! sg' $ f; сделано

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

Please remove me -->

для f в find pages/ -name "*.*"; do perl -i -wpe 'BEGIN {undef $ /} s! <! -. *? -> !! sg' $ f; сделано

//This is single line comment Please remove me.

для f в find pages/ -name "*.*"; do sed -i 's ///.*//' $ f; сделано

Примечание: pages является корневым каталогом, и приведенный выше скрипт найдет и удалит все файлы, расположенные в корневом и подкаталогах.

1 голос
/ 10 июля 2012

Когда я хочу что-то короткое и простое для CSS, я использую это:

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

Это не будет обрабатывать случай, когда разделители комментариев появляются внутри строк, но это намного проще, чем решение, которое делает. Очевидно, что это не пуленепробиваемый или не подходит для всего, но вы знаете лучше, чем педанты на SO, можете ли вы жить с этим или нет.

Я считаю, этот является пуленепробиваемым, однако.

0 голосов
/ 11 ноября 2009

очень упрощенный пример использования gawk. Пожалуйста, протестируйте много раз перед внедрением. Конечно, он не заботится о другом стиле комментария // (в 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...