Làm cách nào tôi có thể xóa tất cả các ký tự thuộc / * '* * / bao gồm / * & * /?


12

Tôi đã thử sed và awk, nhưng nó không hoạt động vì nhân vật liên quan đến "/" đã có sẵn trong lệnh như là dấu phân cách.

Xin vui lòng cho tôi biết làm thế nào tôi có thể đạt được điều này.

Dưới đây là một ví dụ mẫu. Chúng tôi muốn xóa các phần nhận xét tức là /*.....*/

/*This is to print the output
data*/
proc print data=sashelp.cars;
run;
/*Creating dataset*/
data abc;
set xyz;
run;

-bash-4.1 $ sed 's, / *. ** / ,, g' test.sas Dưới đây là thông số tôi nhận được, nhận xét đầu tiên vẫn còn đó. / * Điều này là để in dữ liệu đầu ra * / Proc print data = sashelp.cars; chạy; dữ liệu abc; đặt xyz; chạy;
Sharique Alam

1
Cảm ơn đã chỉnh sửa. Sẽ tốt hơn nữa nếu bạn bao gồm cả đầu ra mong muốn của bạn. Cũng bao gồm những gì bạn đã cố gắng và làm thế nào nó thất bại trong câu hỏi không trong các ý kiến.
terdon

2
Điều gì sẽ xảy ra với chuỗi ký tự chứa các bình luận hoặc dấu phân cách nhận xét? (ví dụ INSERT INTO string_table VALUES('/*'), ('*/'), ('/**/');)
zwol

1
Liên quan (xin lỗi tôi không thể cưỡng lại!): Codegolf.stackexchange.com/questions/48326/ Đổi
ilkkachu

Tôi đã cập nhật bài viết của mình với một giải pháp khác, vui lòng kiểm tra lại nếu bây giờ nó tốt cho bạn.
Luciano Andress Martini

Câu trả lời:


22

Tôi nghĩ rằng tôi đã tìm thấy một giải pháp dễ dàng!

cpp -P yourcommentedfile.txt 

MỘT SỐ CẬP NHẬT:

Trích dẫn từ người dùng ilkachu (văn bản gốc từ các bình luận của người dùng):

Tôi đã chơi một chút với các tùy chọn cho gcc: -fprepered sẽ vô hiệu hóa hầu hết các chỉ thị và mở rộng macro (ngoại trừ #define và #undef rõ ràng). Thêm -dD sẽ để lại định nghĩa quá; và std = c89 có thể được sử dụng để bỏ qua // bình luận kiểu mới. Ngay cả với họ, cpp thay thế các bình luận bằng khoảng trắng (thay vì xóa chúng) và thu gọn khoảng trắng và các dòng trống.

Nhưng tôi nghĩ nó vẫn hợp lý và là một giải pháp dễ dàng cho hầu hết các trường hợp, nếu bạn vô hiệu hóa việc mở rộng macro và những thứ khác tôi nghĩ bạn sẽ có kết quả tốt ... - và vâng, bạn có thể kết hợp điều đó với shell script để cải thiện ... và nhiều hơn nữa...


1
Sử dụng bộ tiền xử lý C có thể là giải pháp mạnh mẽ nhất. Vì bộ tiền xử lý có khả năng là trình phân tích cú pháp C mạnh nhất. Tài giỏi.
hóa dầu

14
Nhưng cppsẽ làm được nhiều hơn là xóa các bình luận (xử lý #include, mở rộng các macro, bao gồm cả các nội dung dựng sẵn ...)
Stéphane Chazelas

3
@LucianoAndressMartini, không, tail -n +7sẽ chỉ xóa 7 dòng đầu tiên, nó sẽ không ngăn chặn việc #includexử lý hoặc mở rộng macro. Hãy thử echo __LINE__ | cppví dụ. Hoặcecho '#include /dev/zero' | cpp
Stéphane Chazelas

2
Bạn có thể muốn sử dụng -Pchế độ nếu bạn làm điều này. (Điều này có thể loại bỏ nhu cầu sử dụng tail.)
zwol

3
Tôi đã chơi một chút với các tùy chọn cho gcc: -fpreprocessedsẽ vô hiệu hóa hầu hết các chỉ thị và mở rộng macro (ngoại trừ #define#undefrõ ràng). Thêm -dDsẽ để lại định nghĩa trong quá; và std=c89có thể được sử dụng để bỏ qua //ý kiến phong cách mới . Ngay cả với chúng, cppthay thế các bình luận bằng khoảng trắng (thay vì xóa chúng) và thu gọn khoảng trắng và các dòng trống.
ilkkachu

10

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}

Giải pháp perl có vấn đề với nhiều dòng: kiểm tra nó với đầu ra này => echo -e "BEGIN / * bình luận * / HÀNH / * com \ nment * / END"
بارپابابا

@Babby, làm việc cho tôi. Tôi đã thêm một nhận xét nhiều dòng và kết quả đầu ra trong trường hợp thử nghiệm của tôi.
Stéphane Chazelas

Điều tốt nhất để so sánh với ngày nay sẽ là gcc -std=c11 -E -P( -ansichỉ là một tên khác cho -std=c90).
zwol

@zwol, ý tưởng là có thể xử lý mã được viết cho bất kỳ tiêu chuẩn C / C ++ nào (c90, c11 hoặc loại khác). Nói đúng ra, điều đó là không thể (xem ví dụ giả định thứ 2 của tôi). Mã vẫn cố xử lý các cấu trúc C90 (như ??'), do đó chúng tôi so sánh với cpp -ansicác cấu trúc đó và C99 / C11 ... một (như // xxx), do đó chúng tôi so sánh với cpp(hoặc cpp -std=c11...)
Stéphane Chazelas

@zwol, tôi đã phân tách trường hợp thử nghiệm để làm rõ một chút. Có vẻ như các bộ ba vẫn còn trong C11, vì vậy trường hợp thử nghiệm thứ hai của tôi không phải là tiêu chuẩn C.
Stéphane Chazelas

6

với sed:

CẬP NHẬT

/\/\*/ {
    /\*\// {
        s/\/\*.*\*\///g;
        b next
    };

    :loop;
    /\*\//! {
        N;
        b loop
    };
    /\*\// {
        s/\/\*.*\*\//\n/g
    }
    :next
}

hỗ trợ tất cả các khả năng (nhận xét nhiều dòng, dữ liệu sau [hoặc và] befor,);

 e1/*comment*/
-------------------
e1/*comment*/e2
-------------------
/*comment*/e2
-------------------
e1/*com
ment*/
-------------------
e1/*com
ment*/e2
-------------------
/*com
ment*/e2
-------------------
e1/*com
1
2
ment*/
-------------------
e1/*com
1
2
ment*/e2
-------------------
/*com
1
2
ment*/e2
-------------------
chạy:
$ sed -f command.sed FILENAME

e1
-------------------
e1e2
-------------------
e2
-------------------
e1

-------------------
e1
e2
-------------------

e2
-------------------
e1

-------------------
e1
e2
-------------------

e2
-------------------

sẽ không làm việc cho một bình luận bắt đầu sau dữ liệu, nhưproc print data 2nd /*another comment is here*/
mazs

@mazs đã cập nhật, hãy kiểm tra nó
بارپابابا

Điều này không xử lý các bình luận bên trong chuỗi ký tự, điều này thực sự có thể quan trọng, tùy thuộc vào những gì SQL làm
zwol

4
 $ cat file | perl -pe 'BEGIN{$/=undef}s!/\*.+?\*/!!sg'

 proc print data=sashelp.cars;
 run;

 data abc;
 set xyz;
 run;

Xóa các dòng trống nếu có:

 $ cat file | perl -pe 'BEGIN{$/=undef}s!/\*.+?\*/\n?!!sg'

Chỉnh sửa - phiên bản ngắn hơn của Stephane:

 $ cat file | perl -0777 -pe 's!/\*.*?\*/!!sg'

tốt, tôi đồng ý với terdon: Hãy xem đầu ra dự kiến.
Hans Schou

BTW: Điều gì sẽ xảy ra với một dòng có chứa: "/ * foo * / run; / * bar * /"? Nếu đó chỉ là "chạy;" ?
Hans Schou

Tuyệt quá! Sau đó, giải pháp của tôi hoạt động. Lưu ý tôi sử dụng không tham lam: ". +?"
Hans Schou

2
Xem -0777như một cách ngắn hơn để làmBEGIN{$/=undef}
Stéphane Chazelas

1
Có lẽ .*?thay vì .+?nếu /**/là một bình luận hợp lệ quá.
ilkkachu

2

Giải pháp bằng cách sử dụng lệnh SED và không có Script

Của bạn đây:

sed 's/\*\//\n&/g' test | sed '/\/\*/,/\*\//d'

NB Điều này không hoạt động trên OS X, trừ khi bạn cài đặt gnu-sed. Nhưng nó hoạt động trên Linux Distros.


1
bạn có thể sử dụng -itùy chọn để chỉnh sửa tệp tại chỗ thay vì chuyển hướng đầu ra sang tệp mới. hoặc an toàn hơn nhiều -i.bakcho tập tin sao lưu
Rahul

1
Nó cũng không hoạt động cho tất cả các trường hợp, hãy thử đặt một nhận xét vào cùng một dòng và xem điều gì xảy ra ... Ví dụ đặt xy \; / * test * / Tôi nghĩ rằng chúng ta sẽ cần perl để giải quyết vấn đề này một cách dễ dàng.
Luciano Andress Martini

@Rahul chính xác, cảm ơn đã đề cập. Tôi chỉ muốn giữ nó đơn giản hơn.
FarazX

Tôi rất xin lỗi để nói rằng nó không hoạt động cho các bình luận trong cùng một dòng.
Luciano Andress Martini

@LucianoAndressMartini Bây giờ thì có!
FarazX

1

sedhoạt động trên một dòng tại một thời điểm, nhưng một số ý kiến ​​trong đầu vào trải dài nhiều dòng. Theo /unix//a/152389/90751 , trước tiên bạn có thể sử dụng trđể biến các ngắt dòng thành một số ký tự khác. Sau đó, sedcó thể xử lý đầu vào dưới dạng một dòng và bạn sử dụng trlại để khôi phục ngắt dòng.

tr '\n' '\0' | sed ... | tr '\0' \n'

Tôi đã sử dụng byte rỗng, nhưng bạn có thể chọn bất kỳ ký tự nào không xuất hiện trong tệp đầu vào của mình.

*có một ý nghĩa đặc biệt trong các biểu thức thông thường, vì vậy nó sẽ cần thoát như \*để khớp với một nghĩa đen *.

.*tham lam - nó sẽ phù hợp với văn bản dài nhất có thể, bao gồm nhiều hơn *//*. Điều đó có nghĩa là bình luận đầu tiên, bình luận cuối cùng và tất cả mọi thứ ở giữa. Để hạn chế điều này, hãy thay thế .*bằng một mẫu chặt chẽ hơn: các bình luận có thể chứa bất cứ thứ gì không phải là "*" và cả "*" kèm theo bất cứ thứ gì không phải là "/". Các lần chạy của nhiều *s cũng phải được tính:

tr '\n' '\0' | sed -e 's,/\*\([^*]\|\*\+[^*/]\)*\*\+/,,g' | tr '\0' '\n'

Điều này sẽ loại bỏ bất kỳ ngắt dòng nào trong các bình luận đa dòng, tức là.

data1 /* multiline
comment */ data2

sẽ trở thành

data1  data2

Nếu đây không phải là điều mong muốn, sedcó thể nói hãy giữ một trong những điểm dừng. Điều này có nghĩa là chọn một ký tự thay thế ngắt dòng có thể được khớp.

tr '\n' '\f' | sed -e 's,/\*\(\(\f\)\|[^*]\|\*\+[^*/]\)*\*\+/,\2,g' | tr '\f' '\n'

Ký tự đặc biệt \fvà việc sử dụng tham chiếu ngược có thể không khớp với bất cứ thứ gì, không được đảm bảo để hoạt động như dự định trong tất cả các sedtriển khai. (Tôi xác nhận nó hoạt động trên GNU sed 4.07 và 4.2.2.)


Bạn có thể vui lòng cho mne biết nó sẽ hoạt động như thế nào không. Tôi đã thử như dưới đây. tr '\ n' '\ 0' | sed -e, / * ([^ *] \ | * \ + [^ * /]) ** \ + / ,, g 'test.sas | tr '\ 0' '\ n' và tôi đã nhận được như sau: / * Đây là để in dữ liệu đầu ra * / data abcdf; đặt cfgtr; chạy; Proc in dữ liệu = sashelp.cars; chạy; dữ liệu abc; đặt xyz; chạy;
Sharique Alam

@ShariqueAlam Bạn đã đặt test.sasở giữa đường ống ở đó, vì vậy sedđọc trực tiếp từ nó, và lần đầu tiên trkhông có hiệu lực. Bạn cần sử dụngcat test.sas | tr ...
JigglyNaga

0

sử dụng một dòng sed để xóa bình luận:

sed '/\/\*/d;/\*\//d' file

proc print data=sashelp.cars;
run;
data abc;
set xyz;
run;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.