Подтвердить что ты не робот

Удалить комментарии из кода C/С++

Есть ли простой способ удалить комментарии из исходного файла C/С++ без предварительной обработки. (т.е. я думаю, что вы можете использовать gcc -E, но это расширит макросы.) Я просто хочу, чтобы исходный код с комментариями был лишен, ничего другого не нужно изменять.

EDIT:

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

4b9b3361

Ответ 1

Запустите следующую команду в вашем исходном файле:

gcc -fpreprocessed -dD -E test.c

Спасибо KennyTM за то, что нашли правильные флаги. Вот результат для полноты:

test.c:

#define foo bar
foo foo foo
#ifdef foo
#undef foo
#define foo baz
#endif
foo foo
/* comments? comments. */
// c++ style comments

gcc -fpreprocessed -dD -E test.c:

#define foo bar
foo foo foo
#ifdef foo
#undef foo
#define foo baz
#endif
foo foo

Ответ 2

Это зависит от того, насколько извращенными являются ваши комментарии. У меня есть программа scc для удаления комментариев C и C++. У меня также есть тестовый файл для него, и я попробовал GCC (4.2.1 на MacOS X) с опциями в текущем выбранном ответе - и GCC, кажется, не справляется с некоторыми из ужасно убитых комментариев в прецедент.

NB: Это не проблема реальной жизни - люди не пишут такой ужасный код.

Рассмотрим (подмножество - 36 из 135 строк) тестового примера:

/\
*\
Regular
comment
*\
/
The regular C comment number 1 has finished.

/\
\/ This is not a C++/C99 comment!

This is followed by C++/C99 comment number 3.
/\
\
\
/ But this is a C++/C99 comment!
The C++/C99 comment number 3 has finished.

/\
\* This is not a C or C++ comment!

This is followed by regular C comment number 2.
/\
*/ This is a regular C comment *\
but this is just a routine continuation *\
and that was not the end either - but this is *\
\
/
The regular C comment number 2 has finished.

This is followed by regular C comment number 3.
/\
\
\
\
* C comment */

На моем Mac вывод из GCC (gcc -fpreprocessed -dD -E subset.c):

/\
*\
Regular
comment
*\
/
The regular C comment number 1 has finished.

/\
\/ This is not a C++/C99 comment!

This is followed by C++/C99 comment number 3.
/\
\
\
/ But this is a C++/C99 comment!
The C++/C99 comment number 3 has finished.

/\
\* This is not a C or C++ comment!

This is followed by regular C comment number 2.
/\
*/ This is a regular C comment *\
but this is just a routine continuation *\
and that was not the end either - but this is *\
\
/
The regular C comment number 2 has finished.

This is followed by regular C comment number 3.
/\
\
\
\
* C comment */

Выходные данные из 'scc':

The regular C comment number 1 has finished.

/\
\/ This is not a C++/C99 comment!

This is followed by C++/C99 comment number 3.
/\
\
\
/ But this is a C++/C99 comment!
The C++/C99 comment number 3 has finished.

/\
\* This is not a C or C++ comment!

This is followed by regular C comment number 2.

The regular C comment number 2 has finished.

This is followed by regular C comment number 3.

Вывод из 'scc -C' (который распознает комментарии с двойной косой чертой):

The regular C comment number 1 has finished.

/\
\/ This is not a C++/C99 comment!

This is followed by C++/C99 comment number 3.

The C++/C99 comment number 3 has finished.

/\
\* This is not a C or C++ comment!

This is followed by regular C comment number 2.

The regular C comment number 2 has finished.

This is followed by regular C comment number 3.

Исходный код для SCC теперь доступен на GitHub

Текущая версия SCC - 6.60 (от 2016-06-12), хотя версии Git были созданы 2017-01-18 (в часовом поясе США/Тихого океана). Код доступен на GitHub по адресу https://github.com/jleffler/scc-snapshots. Вы также можете найти снимки предыдущих выпусков (4.03, 4.04, 5.05) и двух предварительных выпусков (6.16, 6.50) - все они помечены как release/x.yz

Код до сих пор в основном разрабатывается под RCS. Я все еще работаю над тем, как я хочу использовать stderr.c или аналогичный механизм для работы с общими библиотеками, такими как stderr.c и stderr.h (которые также можно найти по адресу https://github.com/jleffler/soq).,

Версия 6.60 SCC пытается понять конструкции C++ 11, C++ 14 и C++ 17, такие как двоичные константы, числовая пунктуация, необработанные строки и шестнадцатеричные числа с плавающей запятой. По умолчанию используется режим C11. (Обратите внимание, что значение флага -C - упомянутое выше - переключалось между версией 4.0x, описанной в основном тексте ответа, и версией 6.60, которая в настоящее время является последней версией.)

Ответ 3

gcc -fpreprocessed -dD -E не работал у меня, но эта программа делает это:

#include <stdio.h>

static void process(FILE *f)
{
 int c;
 while ( (c=getc(f)) != EOF )
 {
  if (c=='\'' || c=='"')            /* literal */
  {
   int q=c;
   do
   {
    putchar(c);
    if (c=='\\') putchar(getc(f));
    c=getc(f);
   } while (c!=q);
   putchar(c);
  }
  else if (c=='/')              /* opening comment ? */
  {
   c=getc(f);
   if (c!='*')                  /* no, recover */
   {
    putchar('/');
    ungetc(c,f);
   }
   else
   {
    int p;
    putchar(' ');               /* replace comment with space */
    do
    {
     p=c;
     c=getc(f);
    } while (c!='/' || p!='*');
   }
  }
  else
  {
   putchar(c);
  }
 }
}

int main(int argc, char *argv[])
{
 process(stdin);
 return 0;
}

Ответ 4

Существует программа stripcmt, чем это можно сделать:

StripCmt - простая утилита, написанная на C для удаления комментариев из исходных файлов C, С++ и Java. В великой традиции программ обработки текста Unix он может функционировать либо как фильтр FIFO (First In-First Out), либо принимать аргументы в командной строке.

(за hlovdal ответьте на вопрос о коде Python для этого)

Ответ 5

Это perl script, чтобы удалить//однострочный и /* многострочный */комментарии

  #!/usr/bin/perl

  undef $/;
  $text = <>;

  $text =~ s/\/\/[^\n\r]*(\n\r)?//g;
  $text =~ s/\/\*+([^*]|\*(?!\/))*\*+\///g;

  print $text;

Он требует, чтобы ваш исходный файл был аргументом командной строки. Сохраните script в файл, скажем remove_comments.pl и вызовите его, используя следующую команду: perl -w remove_comments.pl [ваш исходный файл]

Надеюсь, что это будет полезно

Ответ 6

У меня тоже была эта проблема. Я нашел этот инструмент (Cpp-Decomment), который работал у меня. Однако он игнорирует, если строка комментария продолжается до следующей строки. Например:

// this is my comment \
comment continues ...

В этом случае я не мог найти способ в программе, поэтому просто искал строки и фиксировал их вручную. Я считаю, что для этого был бы вариант или, возможно, вы могли бы изменить исходный файл программы для этого.

Ответ 7

Поскольку вы используете C, вы можете использовать что-то, что "естественно" для C. Вы можете использовать препроцессор C, чтобы просто удалять комментарии. Приведенные ниже примеры работают с препроцессором C из GCC. Они должны работать одинаково или аналогично с другими процессорами C.

Для C используйте

cpp -dD -fpreprocessed -o output.c input.c

Он также работает для удаления комментариев от JSON, например:

cpp -P -o - - <input.json >output.json

Если ваш препроцессор C недоступен напрямую, вы можете попробовать заменить cpp на cc -E, который вызывает компилятор C, говорящий ему прекратить работу после этапа препроцессора. В случае, если ваш компилятор C не является cc, вы можете заменить cc на имя своего двоичного файла компилятора C, например clang. Обратите внимание, что не все препроцессоры поддерживают -fpreprocessed.

Ответ 8

Я пишу C-программу, используя стандартную C-библиотеку, около 200 строк, которая удаляет комментарии из файла с исходным кодом на C. qeatzy/removeccomments

поведение

  1. Комментарий в стиле C, занимающий несколько строк или занимающий всю строку, обнуляется.
  2. Комментарий в стиле C в середине строки остается без изменений. например, void init(/* do initialization */) {...}
  3. Комментарий стиля C++, занимающий всю строку, обнуляется.
  4. Строковый литерал C соблюдается, проверяя " и \".
  5. обрабатывает продолжение строки. Если предыдущая строка заканчивается на \, текущая строка является частью предыдущей строки.
  6. номер строки остается прежним. Вычеркнутые строки или часть строки становятся пустыми.

тестирование и профилирование

Я тестировал самый большой исходный код cpython, который содержит много комментариев. В этом случае он делает работу правильно и быстро, в 2-5 раз быстрее, чем gcc

time gcc -fpreprocessed -dD -E Modules/unicodeobject.c > res.c 2>/dev/null
time ./removeccomments < Modules/unicodeobject.c > result.c

использование

/path/to/removeccomments < input_file > output_file

Ответ 9

Я верю Если вы используете одно выражение, вы можете легко удалить Комментарии из C

perl -i -pe ‘s/\\\*(.*)/g’ file.c This command Use for removing * C style comments 
perl -i -pe 's/\\\\(.*)/g' file.cpp This command Use for removing \ C++ Style Comments

Только проблема с этой командой не удаляет комментарии, содержащие более одной строки. Но с помощью этого regEx вы можете легко реализовать логику для комментариев Multiline Removing

Ответ 10

Недавно я написал код на Ruby для решения этой проблемы. Я рассмотрел следующие исключения:

  • комментарий в строках
  • многострочный комментарий на одной строке, исправление жадного совпадения.
  • несколько строк на несколько строк

Вот код:

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

  • MUL_REPLACE_LEFT = " MUL_REPLACE_LEFT "
  • MUL_REPLACE_RIGHT = " MUL_REPLACE_RIGHT "
  • SIG_REPLACE = " SIG_REPLACE "

ИСПОЛЬЗОВАНИЕ: ruby -w inputfile outputfile

Ответ 11

Я знаю это поздно, но я решил поделиться своим кодом и первой попыткой написать компилятор.

Примечание. Это не учитывает "\*/" внутри многострочного комментария, например, /\*...."*/"...\*. Опять же, gcc 4.8.1 тоже не работает.

void function_removeComments(char *pchar_sourceFile, long long_sourceFileSize)
{
    long long_sourceFileIndex = 0;
    long long_logIndex = 0;

    int int_EOF = 0;

    for (long_sourceFileIndex=0; long_sourceFileIndex < long_sourceFileSize;long_sourceFileIndex++)
    {
        if (pchar_sourceFile[long_sourceFileIndex] == '/' && int_EOF == 0)
        {
            long_logIndex = long_sourceFileIndex;  // log "possible" start of comment

            if (long_sourceFileIndex+1 < long_sourceFileSize)  // array bounds check given we want to peek at the next character
            {
                if (pchar_sourceFile[long_sourceFileIndex+1] == '*') // multiline comment
                {
                    for (long_sourceFileIndex+=2;long_sourceFileIndex < long_sourceFileSize; long_sourceFileIndex++)
                    {
                        if (pchar_sourceFile[long_sourceFileIndex] == '*' && pchar_sourceFile[long_sourceFileIndex+1] == '/')
                        {
                            // since we've found the end of multiline comment
                            // we want to increment the pointer position two characters
                            // accounting for "*" and "/"
                            long_sourceFileIndex+=2;  

                            break;  // terminating sequence found
                        }
                    }

                    // didn't find terminating sequence so it must be eof.
                    // set file pointer position to initial comment start position
                    // so we can display file contents.
                    if (long_sourceFileIndex >= long_sourceFileSize)
                    {
                        long_sourceFileIndex = long_logIndex;

                        int_EOF = 1;
                    }
                }
                else if (pchar_sourceFile[long_sourceFileIndex+1] == '/')  // single line comment
                {
                    // since we know its a single line comment, increment file pointer
                    // until we encounter a new line or its the eof 
                    for (long_sourceFileIndex++; pchar_sourceFile[long_sourceFileIndex] != '\n' && pchar_sourceFile[long_sourceFileIndex] != '\0'; long_sourceFileIndex++);
                }
            }
        }

        printf("%c",pchar_sourceFile[long_sourceFileIndex]);
     }
 }

Ответ 12

#include<stdio.h>
{        
        char c;
        char tmp = '\0';
        int inside_comment = 0;  // A flag to check whether we are inside comment
        while((c = getchar()) != EOF) {
                if(tmp) {
                        if(c == '/') {
                                while((c = getchar()) !='\n');
                                tmp = '\0';
                                putchar('\n');
                                continue;
                        }else if(c == '*') {
                                inside_comment = 1;
                                while(inside_comment) {
                                        while((c = getchar()) != '*');
                                        c = getchar();
                                        if(c == '/'){
                                                tmp = '\0';
                                                inside_comment = 0;
                                        }
                                }
                                continue;
                        }else {
                                putchar(c);
                                tmp = '\0';
                                continue;
                        }
                }
                if(c == '/') {
                        tmp = c;
                } else {
                        putchar(c);
                }
        }
        return 0;
}

Эта программа выполняется для обоих условий i.e//и/...../