Я одного разу придумав таке, що ми можемо вдосконалити:
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% c% s% s% d \ n",
1 - / * коментар * / - 1,
/ \
* коментар * /
"/ * не коментар * /",
/ * багаторядковий
коментар * /
'"' / * коментар * /, '"',
'\' ',' "'/ * коментар * /,
'\
\
"', / * коментар * /
"\\
"/ * не коментар * /",
"?? /" / * не коментар * / ",
'??' '+' "'/ *" коментар "* /);
повернути 0;
}
Що дає цей вихід:
#include <stdio.h>
int main ()
{
printf ("% d% s% c% 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}