Удалить комментарии из кода C/С++
Есть ли простой способ удалить комментарии из исходного файла C/С++ без предварительной обработки. (т.е. я думаю, что вы можете использовать gcc -E, но это расширит макросы.) Я просто хочу, чтобы исходный код с комментариями был лишен, ничего другого не нужно изменять.
EDIT:
Предпочтение к существующему инструменту. Я не хочу писать это сам с помощью регулярных выражений, я предвижу слишком много сюрпризов в коде.
Ответы
Ответ 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
поведение
- Комментарий в стиле C, занимающий несколько строк или занимающий всю строку, обнуляется.
- Комментарий в стиле C в середине строки остается без изменений. например,
void init(/* do initialization */) {...}
- Комментарий стиля C++, занимающий всю строку, обнуляется.
- Строковый литерал C соблюдается, проверяя
"
и \"
. - обрабатывает продолжение строки. Если предыдущая строка заканчивается на
\
, текущая строка является частью предыдущей строки. - номер строки остается прежним. Вычеркнутые строки или часть строки становятся пустыми.
тестирование и профилирование
Я тестировал самый большой исходный код 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//и/...../