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

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

Ответ 1

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

[Редактировать] Этот подход также отлично обрабатывает сценарий Barts 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;
}

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

Ответ 2

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

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

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

Ответ 3

Взгляните на процедуру 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;
}

Ответ 4

Пожалуйста, не используйте 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;
}

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

Ответ 5

Рассмотрим:

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

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

Ответ 6

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

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

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

Ответ 7

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

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.

Ответ 8

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

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

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

Я верю этот.

Ответ 9

Попробуйте рекурсивный способ поиска и удаления комментариев типа Java script, комментарии типа 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///.*//'$ f; сделано

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

Ответ 10

очень упрощенный пример с использованием gawk. Протестируйте много раз перед реализацией. Конечно, он не заботится о другом стиле комментариев//(в С++??)

$ 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;