Как я могу удалить все символы, попадающие в / *… * /, включая / * & * /?

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

12
21.07.2016, 14:07
9 ответов

Я думаю, что нашел простое решение!

cpp -P yourcommentedfile.txt 

НЕКОТОРЫЕ ОБНОВЛЕНИЯ:

Цитата пользователя ilkachu (исходный текст из комментариев пользователя):

Я немного поигрался с параметрами gcc: -fpreprocessed отключит большинство директив и расширений макросов (кроме #define и #undef, очевидно). Добавление -dD также оставит определения; и std = c89 можно использовать для игнорирования // комментариев нового стиля. Даже с ними cpp заменяет комментарии пробелами (вместо их удаления) и сворачивает пробелы и пустые строки.

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

22
27.01.2020, 19:54

с sed :

ОБНОВЛЕНИЕ

/\/\*/ {
    /\*\// {
        s/\/\*.*\*\///g;
        b next
    };

    :loop;
    /\*\//! {
        N;
        b loop
    };
    /\*\// {
        s/\/\*.*\*\//\n/g
    }
    :next
}

поддерживает все возможные (многострочный комментарий, данные после [или и] до,);

 e1/*comment*/
-------------------
e1/*comment*/e2
-------------------
/*comment*/e2
-------------------
e1/*com
ment*/
-------------------
e1/*com
ment*/e2
-------------------
/*com
ment*/e2
-------------------
e1/*com
1
2
ment*/
-------------------
e1/*com
1
2
ment*/e2
-------------------
/*com
1
2
ment*/e2
-------------------
запустить: {{1 }}
$ sed -f command.sed FILENAME

e1
-------------------
e1e2
-------------------
e2
-------------------
e1

-------------------
e1
e2
-------------------

e2
-------------------
e1

-------------------
e1
e2
-------------------

e2
-------------------
6
27.01.2020, 19:54

Однажды я придумал этот , который мы можем уточнить до:

perl -0777 -pe '
  BEGIN{
    $bs=qr{(?:\\|\?\?/)};
    $lc=qr{(?:$bs\n|$bs\r\n?)}
  }
  s{
    /$lc*\*.*?\*$lc*/
    | /$lc*/(?:$lc|[^\r\n])*
    | (
         "(?:$bs$lc*.|.)*?"
       | '\''$lc*(?:$bs$lc*(?:\?\?.|.))?(?:\?\?.|.)*?'\''
       | \?\?'\''
       | .[^'\''"/?]*
      )
  }{$1 eq "" ? " " : "$1"}exsg'

, чтобы обработать еще несколько угловых случаев.

Обратите внимание, что если вы удалите комментарий, вы можете изменить значение кода ( 1 - / * комментарий * / - 1 анализируется как 1 - - 1 , а 1–1 (который вы получите, если удалите комментарий) даст вам ошибку). Лучше заменить комментарий пробелом (как мы это делаем здесь), а не полностью удалять его.

Вышеупомянутое должно правильно работать с этим допустимым кодом ANSI C, например, который пытается включить несколько угловых случаев:

#include <stdio.h>
int main()
{
  printf("%d %s %c%c%c%c%c %s %s %d\n",
  1-/* comment */-1,
  /\
* comment */
  "/* not a comment */",
  /* multiline
  comment */
  '"' /* comment */ , '"',
  '\'','"'/* comment */,
  '\
\
"', /* comment */
  "\\
" /* not a comment */ ",
  "??/" /* not a comment */ ",
  '??''+'"' /* "comment" */);
  return 0;
}

Что дает следующий результат:

#include <stdio.h>
int main()
{
  printf("%d %s %c%c%c%c%c %s %s %d\n",
  1- -1,

  "/* not a comment */",

  '"'   , '"',
  '\'','"' ,
  '\
\
"',  
  "\\
" /* not a comment */ ",
  "??/" /* not a comment */ ",
  '??''+'"'  );
  return 0;
}

Оба печатают один и тот же результат при компиляции и запуске.

Вы можете сравнить с выводом gcc -ansi -E , чтобы увидеть, что препроцессор сделает с ним.Этот код также является допустимым кодом C99 или C11, однако gcc по умолчанию отключает поддержку триграфов, поэтому он не будет работать с gcc , если вы не укажете стандарт, например gcc -std = c99 или gcc -std = c11 или добавьте параметр -trigraphs ).

Он также работает с этим кодом C99 / C11 (не ANSI / C90):

// comment
/\
/ comment
// multiline\
comment
"// not a comment"

(сравните с gcc -E / gcc -std = c99 -E / gcc -std = c11 -E )

ANSI C не поддерживает форму // комментария. // иначе недопустимо в ANSI C, поэтому не будет там отображаться. Один надуманный случай, когда // может действительно появиться в ANSI C (как отмечено там , и вы можете найти интересную остальную часть обсуждения), когда stringify оператор уже используется.

Это действующий код ANSI C:

#define s(x) #x
s(//not a comment)

И во время обсуждения в 2004 году gcc -ansi -E действительно расширил его до «// не комментарий» . Однако сегодня gcc-5.4 возвращает ошибку, поэтому я сомневаюсь, что мы найдем много кода C, использующего такую ​​конструкцию.

Эквивалент GNU sed может выглядеть примерно так:

lc='([\\%]\n|[\\%]\r\n?)'
sed -zE "
  s/_/_u/g;s/!/_b/g;s/</_l/g;s/>/_r/g;s/:/_c/g;s/;/_s/g;s/@/_a/g;s/%/_p/g;
  s@\?\?/@%@g;s@/$lc*\*@:&@g;s@\*$lc*/@;&@g
  s:/$lc*/:@&:g;s/\?\?'/!/g
  s#:/$lc*\*[^;]*;\*$lc*/|@/$lc*/$lc*|(\"([\\\\%]$lc*.|[^\\\\%\"])*\"|'$lc*([\\\\%]$lc*.)?[^\\\\%']*'|[^'\"@;:]+)#<\5>#g
  s/<>/ /g;s/!/??'/g;s@%@??/@g;s/[<>@:;]//g
  s/_p/%/g;s/_a/@/g;s/_s/;/g;s/_c/:/g;s/_r/>/g;s/_l/</g;s/_b/!/g;s/_u/_/g"

Если ваш GNU sed слишком стар, чтобы поддерживать -E или -z , вы можете заменить первую строку на:

sed -r ":1;\$!{N;b1}
11
27.01.2020, 19:54
 $ cat file | perl -pe 'BEGIN{$/=undef}s!/\*.+?\*/!!sg'

 proc print data=sashelp.cars;
 run;

 data abc;
 set xyz;
 run;

Удалите пустые строки, если они есть:

 $ cat file | perl -pe 'BEGIN{$/=undef}s!/\*.+?\*/\n?!!sg'

Edit - более короткая версия Стефана:

 $ cat file | perl -0777 -pe 's!/\*.*?\*/!!sg'
4
27.01.2020, 19:54

Решение с использованием команды SED без сценария

Вот и вы:

sed 's / \ * \ // \ n & / g' test | sed '/\/\*/,/\*\//d'

N.B. Это не работает в OS X, если вы не установите gnu-sed . Но он работает в дистрибутивах Linux.

2
27.01.2020, 19:54

sed работает с одной строкой за раз, но некоторые комментарии на входе несколько строк. Согласно https://unix.stackexchange.com/a/152389/90751 , вы можете сначала использовать tr , чтобы преобразовать перенос строки в какой-либо другой символ. Затем sed может обрабатывать ввод как одну строку, и вы снова используете tr , чтобы восстановить разрывы строк.

tr '\n' '\0' | sed ... | tr '\0' \n'

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

* имеет особое значение в регулярных выражениях, поэтому для соответствия литералу * потребуется экранирование как \ * .

. * жадный - он будет соответствовать максимально длинному тексту, включая дополнительные * / и / * . Это означает первый комментарий, последний комментарий и все, что между ними. Чтобы ограничить это, замените . * более строгим шаблоном: комментарии могут содержать все, что не является «*», а также «*», за которым следует все, кроме «/». Также необходимо учитывать выполнение нескольких * s:

tr '\n' '\0' | sed -e 's,/\*\([^*]\|\*\+[^*/]\)*\*\+/,,g' | tr '\0' '\n'

Это удалит любые разрывы строк в многострочных комментариях, т.е.

data1 /* multiline
comment */ data2

превратится в

data1  data2

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

tr '\n' '\f' | sed -e 's,/\*\(\(\f\)\|[^*]\|\*\+[^*/]\)*\*\+/,\2,g' | tr '\f' '\n'

Специальный символ \ f и использование обратной ссылки, которая, возможно, не соответствует чему-либо, не гарантируют правильную работу во всех реализациях sed . (Я подтвердил, что он работает на GNU sed 4.07 и 4.2.2.)

1
27.01.2020, 19:54

с использованием одной строки sed для удаления комментариев:

sed '/\/\*/d;/\*\//d' file

proc print data=sashelp.cars;
run;
data abc;
set xyz;
run;
0
27.01.2020, 19:54

В руководстве по GNU awk приводится пример с getline , который делает именно то, что я копирую здесь дословно.

# Remove text between /* and */, inclusive
{
    while ((start = index($0, "/*")) != 0) {
        out = substr($0, 1, start - 1)  # leading part of the string
        rest = substr($0, start + 2)    #... */...    
        while ((end = index(rest, "*/")) == 0) {  # is */ in trailing part?
            # get more text
            if (getline <= 0) {
                print("unexpected EOF or error:", ERRNO) > "/dev/stderr"
                exit
            }
            # build up the line using string concatenation
            rest = rest $0
        }
        rest = substr(rest, end + 2)  # remove comment
        # build up the output line using string concatenation
        $0 = out rest
    }
    print $0
}

Имейте в виду, что он соединяет mon/*comment*/keyс monkey. Как упоминает Стефан Шазелас в этом ответе, это может привести к эффективному другому коду, поэтому рассмотрите возможность изменения $0 = out restна $0 = out " " rest.

Сохраните это в файле, например commentRemove.awk, и выполните его наinputfile:

awk -f commentRemove.awk inputfile
0
11.07.2020, 20:10

Почему бы не использовать препроцессор cpp ()?

( sed "s,^\(\s*\)#,\1_:#:_," \
| sed "s,\\\\$,_:%:_," \
| cpp \
| sed "/^\s*#/ d" \
| sed "s,^\(\s*\)_:#:_,\1#," \
| sed "s,_:%:_$,\\\\," \
) < in.c > out.c
0
21.07.2020, 09:53

Теги

Похожие вопросы