Tôi đã từng nghĩ ra cái này mà chúng ta có thể tinh chỉnh:
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'
để xử lý một vài trường hợp góc.
Lưu ý rằng nếu bạn xóa một nhận xét, bạn có thể thay đổi ý nghĩa của mã ( 1-/* comment */-1
được phân tích cú pháp như 1 - -1
while 1--1
(mà bạn nhận được nếu bạn xóa nhận xét) sẽ gây ra lỗi cho bạn). Tốt hơn là thay thế nhận xét bằng một ký tự khoảng trắng (như chúng ta làm ở đây) thay vì xóa hoàn toàn nó.
Ví dụ ở trên phải hoạt động chính xác trên mã ANSI C hợp lệ này, ví dụ như cố gắng bao gồm một vài trường hợp góc:
#inc loại <stdio.h>
int chính ()
{
printf ("% d% s% c% c% c% c% c% s% s% d \ n",
1 - / * nhận xét * / - 1,
/ \
* bình luận */
"/ * không phải là một bình luận * /",
/ * đa dòng
bình luận */
'"' /* bình luận */ , '"',
'\'','"'/* bình luận */,
'\
\
"', /* bình luận */
"
"/ * không phải là một bình luận * /",
"?? /" / * không phải là nhận xét * / ",
'??' '+' "'/ *" bình luận "* /);
trả về 0;
}
Cung cấp đầu ra này:
#inc loại <stdio.h>
int chính ()
{
printf ("% d% s% c% c% c% c% c% s% s% d \ n",
1- -1,
"/ * không phải là một bình luận * /",
'"', '"',
'\' ',' "',
'\
\
"',
"
"/ * không phải là một bình luận * /",
"?? /" / * không phải là nhận xét * / ",
'??' '+' "');
trả về 0;
}
Cả hai đều in cùng một đầu ra khi biên dịch và chạy.
Bạn có thể so sánh với đầu ra gcc -ansi -E
để xem bộ xử lý trước sẽ làm gì với nó. Mã mà cũng là C99 hợp lệ hoặc mã C11, tuy nhiên gcc
vô hiệu hóa trigraphs hỗ trợ theo mặc định vì nó sẽ không làm việc với gcc
trừ khi bạn chỉ định tiêu chuẩn như gcc -std=c99
hoặc gcc -std=c11
hoặc thêm -trigraphs
tùy chọn).
Nó cũng hoạt động trên mã C99 / C11 (không phải ANSI / C90) này:
// bình luận
/ \
/ bình luận
// đa dòng \
bình luận
"// không bình luận"
(so sánh với gcc -E
/ gcc -std=c99 -E
/ gcc -std=c11 -E
)
ANSI C không hỗ trợ // form
bình luận. //
không hợp lệ trong ANSI C nên sẽ không xuất hiện ở đó. Một trường hợp giả tạo nơi //
thực sự có thể xuất hiện trong ANSI C (như đã nói ở đó , và bạn có thể tìm thấy phần còn lại của thú thảo luận) là khi stringify điều hành được sử dụng.
Đây là mã ANSI C hợp lệ:
#define s(x) #x
s(//not a comment)
Và tại thời điểm thảo luận năm 2004, gcc -ansi -E
thực sự đã mở rộng nó sang "//not a comment"
. Tuy nhiên, hôm nay, gcc-5.4
trả về một lỗi trên đó, vì vậy tôi nghi ngờ chúng ta sẽ tìm thấy rất nhiều mã C sử dụng loại cấu trúc này.
sed
Tương đương GNU có thể là một cái gì đó như:
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"
Nếu GNU của bạn sed
quá cũ để hỗ trợ -E
hoặc -z
, bạn có thể thay thế dòng đầu tiên bằng:
sed -r ":1;\$!{N;b1}