Kiedyś wpadłem na pomysł, który możemy udoskonalić:
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'
aby obsłużyć jeszcze kilka skrzynek narożnych
Zauważ, że jeśli usuniesz komentarz, możesz zmienić znaczenie kodu ( 1-/* comment */-1parsowane jak 1 - -1podczas while 1--1(które uzyskasz , jeśli usuniesz komentarz) spowoduje błąd). Lepiej zastąpić komentarz spacją (tak jak tutaj), zamiast całkowicie go usunąć.
Powyższe powinno działać poprawnie na tym poprawnym kodzie ANSI C, na przykład, który próbuje uwzględnić kilka przypadków narożnych:
#include <stdio.h>
int main ()
{
printf ("% d% s% c% c% c% c% c% s% s% d \ n",
1 - / * komentarz * / - 1,
/ \
* komentarz */
„/ * nie jest komentarzem * /”,
/ * multiline
komentarz */
'"' /* komentarz */ , '"',
'\'','"'/* komentarz */,
„\
\
"', /* komentarz */
„\\
„/ * nie jest komentarzem * /”,
„?? /” / * not a comment * / ”,
„??” „+” „” / * „komentarz” * /);
zwraca 0;
}
Co daje ten wynik:
#include <stdio.h>
int main ()
{
printf ("% d% s% c% c% c% c% c% s% s% d \ n",
1- -1
„/ * nie jest komentarzem * /”,
„” „” „”
„\”, „”
„\
\
„”,
„\\
„/ * nie jest komentarzem * /”,
„?? /” / * not a comment * / ”,
„??” „+” „);
zwraca 0;
}
Oba drukują ten sam wynik po kompilacji i uruchomieniu.
Możesz porównać z wyjściem, gcc -ansi -Eaby zobaczyć, co zrobiłby na nim procesor wstępny. Ten kod jest również prawidłowym kodem C99 lub C11, jednak gccdomyślnie wyłącza obsługę trigrafów, więc nie będzie działać, gccchyba że określisz standard, gcc -std=c99lub gcc -std=c11lub dodasz -trigraphsopcję).
Działa również z tym kodem C99 / C11 (nie ANSI / C90):
// komentarz
/ \
/ komentarz
// multiline \
komentarz
„// bez komentarza”
(porównaj z gcc -E/ gcc -std=c99 -E/ gcc -std=c11 -E)
ANSI C nie obsługiwał // formkomentarza. //nie jest inaczej ważne w ANSI C, więc nie pojawi się tam. Jednym z wymyślonych przypadków, w których //może rzeczywiście pojawić się w ANSI C (jak tam wspomniano , a resztę dyskusji może okazać się interesująca), jest użycie operatora strunizacji .
To jest poprawny kod ANSI C:
#define s(x) #x
s(//not a comment)
I w czasie dyskusji w 2004 r. gcc -ansi -ERzeczywiście ją rozszerzyłem "//not a comment". Jednak dzisiaj gcc-5.4zwraca błąd, więc wątpię, abyśmy znaleźli dużo kodu C przy użyciu tego rodzaju konstrukcji.
Odpowiednikiem GNU sedmoże być coś takiego:
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"
Jeśli GNU sedjest zbyt stary, by wspierać -Elub -zmożna wymienić pierwszą linię z:
sed -r ":1;\$!{N;b1}