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 - -1while 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 gccvô hiệu hóa trigraphs hỗ trợ theo mặc định vì nó sẽ không làm việc với gcctrừ khi bạn chỉ định tiêu chuẩn như gcc -std=c99hoặc gcc -std=c11hoặc thêm -trigraphstù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ợ // formbì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 -Ethực sự đã mở rộng nó sang "//not a comment". Tuy nhiên, hôm nay, gcc-5.4trả 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.
sedTươ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 sedquá cũ để hỗ trợ -Ehoặc -z, bạn có thể thay thế dòng đầu tiên bằng:
sed -r ":1;\$!{N;b1}