Однажды я придумал это, что мы можем улучшить:
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-/* comment */-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 - / * комментарий * / - 1,
/ \
* комментарий * /
"/ * не комментарий * /",
/ * многострочный
комментарий * /
'"' / * comment * /, '"',
'\' ',' "'/ * комментарий * /,
«\
\
"', / * комментарий * /
«\\
"/ * не комментарий * /",
"?? /" / * не комментарий * / ",
'??' '+' "'/ *" comment "* /);
вернуть 0;
}
Что дает этот вывод:
#include <stdio.h>
int main ()
{
printf («% d% s% c% c% c% c% c% s% s% d \ n»,
1- -1,
"/ * не комментарий * /",
'' ',' "',
'\' ',' "',
«\
\
«»,
«\\
"/ * не комментарий * /",
"?? /" / * не комментарий * / ",
'??' '+' "');
вернуть 0;
}
Оба печатают один и тот же вывод при компиляции и запуске.
Вы можете сравнить с выводом, gcc -ansi -Eчтобы увидеть, что будет делать на нем препроцессор. Этот код также действует C99 или C11 код, однако gccотключает триграфы поддержки по умолчанию , поэтому он не будет работать с , gccесли не указано стандартом , как gcc -std=c99или gcc -std=c11или добавить -trigraphsопцию).
Он также работает с этим кодом C99 / C11 (не ANSI / C90):
// комментарий
/ \
/ комментарий
// многострочный \
комментарий
"// не комментарий"
(сравнить с gcc -E/ gcc -std=c99 -E/ gcc -std=c11 -E)
ANSI C не поддерживает // formкомментарий. //иначе не действует в ANSI C, поэтому не появится там. Один надуманный случай, когда //в ANSI C может действительно появиться (как отмечено там , а остальная часть обсуждения может оказаться интересной), это когда используется оператор stringify .
Это действительный код ANSI C:
#define s(x) #x
s(//not a comment)
И во время обсуждения в 2004 году gcc -ansi -Eдействительно расширилось до "//not a comment". Однако сегодня gcc-5.4возвращает ошибку, поэтому я сомневаюсь, что мы найдем много кода на C, использующего такую конструкцию.
sedЭквивалентом GNU может быть что-то вроде:
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}