/ *および* /を含む/ *…* /に該当するすべての文字を削除するにはどうすればよいですか?


12

私はsedとawkを試しましたが、文字には区切り文字としてコマンドに既に存在する「/」が含まれるため、動作しません。

これを達成する方法を教えてください。

以下にサンプルの例を示します。コメントされたセクションを削除します。 /*.....*/

/*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以下は私が得た出力で、最初のコメントはまだあります。/ *これは出力データを印刷します* / proc print data = sashelp.cars; 走る; データabc; xyzを設定します。走る;
シャリクアラム

1
編集してくれてありがとう。目的の出力も含めておくとさらに良いでしょう。また、コメントではなく質問にあなたが試したものと失敗した方法を含めてください。
テルドン

2
コメントまたはコメント区切り文字を含む文字列リテラルはどうなりますか?(例INSERT INTO string_table VALUES('/*'), ('*/'), ('/**/');
-zwol

1
関連(申し訳ありませんが、私は抵抗することはできません!):codegolf.stackexchange.com/questions/48326/...
ilkkachu

投稿を別のソリューションで更新しました。今それがあなたに適しているかどうか再確認してください。
ルチアーノアンドレスマティーニ

回答:


22

私は簡単な解決策を見つけたと思います!

cpp -P yourcommentedfile.txt 

いくつかの更新:

ユーザーilkachuからの引用(ユーザーコメントの元のテキスト):

gccのオプションを少し試しました-fpreprocessedは、ほとんどのディレクティブとマクロ展開を無効にします(明らかに#defineと#undefを除く)。-dDを追加すると、定義も残ります。およびstd = c89を使用して、新しいスタイルの//コメントを無視できます。それらを使用しても、cppはコメントを(削除する代わりに)スペースに置き換え、スペースと空行を折りたたみます。

しかし、マクロ展開などを無効にすると、良い結果が得られると思いますが、ほとんどの場合、それはまだ合理的で簡単な解決策だと思います... ...などなど...


1
Cプリプロセッサを使用することが、おそらく最も堅牢なソリューションです。プリプロセッサはおそらくCコメントの最も堅牢なパーサーであるためです。賢い。
-grochmal

14
ただし、cppコメントを削除するだけではありません(処理#include、組み込みマクロを含むマクロの展開...)
StéphaneChazelas 16

3
@LucianoAndressMartini、いいえ、tail -n +7最初の7行を削除するだけで、#include処理やマクロの展開を妨げません。echo __LINE__ | cpp例えば試してみてください。それともecho '#include /dev/zero' | cpp
ステファンChazelas

2
-Pこれを行う場合は、おそらくモードを使用する必要があります。(これにより、使用する必要がなくなる場合がありますtail。)
zwol

3
私はgccのオプションを少し試しました:-fpreprocessedほとんどのディレクティブとマクロ展開を無効にします(ただし#define#undef明らかにそうではありません)。追加-dDしても定義はそのままになります。そしてstd=c89新しいスタイルを無視するために使用することができます//コメントを。それらを使用しても、cppコメントを削除する代わりにスペースで置き換え、スペースと空行を折りたたみます。
-ilkkachu

10

私はかつてこれを思いつきました。

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'

いくつかのコーナーケースを処理します。

コメントを削除すると、コードの意味を変更できることに注意してください(whileの1-/* comment */-1ように解析されます(コメントを削除した場合に取得します)はエラーになります)。コメントを完全に削除するのではなく、(ここで行っているように)コメントをスペース文字で置き換える方が適切です。1 - -11--1

上記は、いくつかのコーナーケースを含めようとするこの有効なANSI Cコードで適切に動作するはずです。

#include <stdio.h>
int main()
{
  printf( "%d%s%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%s%s%d \ n"、
  1- -1

  「/ *コメントではありません* /」、

  '"'、 '"'、
  '\' '、' "'、
  '\
\
「 '、  
  「\\
"/ *コメントではありません* /"、
  "?? /" / *コメントではありません* / "、
  '??' '+' "');
  0を返します。
}

両方とも、コンパイルおよび実行時に同じ出力を印刷します。

の出力と比較して、gcc -ansi -Eプリプロセッサがそれに対して何を行うかを確認できます。このコードは有効なC99またはC11コードでもありますがgcc、デフォルトでtrigraphsサポートを無効にしているためgcc、標準のような指定gcc -std=c99やオプションのgcc -std=c11追加を行わない限り機能しません-trigraphs

このC99 / C11(非ANSI / C90)コードでも機能します。

//コメント
/ \
/コメント
//複数行\
コメント
「//コメントではありません」

gcc -E/ gcc -std=c99 -E/ と比較gcc -std=c11 -E

ANSI Cは// formofコメントをサポートしていません。//それ以外の場合は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コードが多数見つかるとは思いません。

GNUにsed相当するものは次のようなものです。

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}

テストそれこの出力を持つ=>エコー-e "BEGIN / *コメント* / COMMAND / * COM \ nment * / END":perlのソリューションは、複数行に問題が持っている
بارپابابا

@Babby、私のために働いています。テストケースに複数行のコメントと結果の出力を追加しました。
ステファンシャゼル16

今日と比較するのに最適なのはgcc -std=c11 -E -P(の-ansi別名にすぎない-std=c90)です。
zwol

@zwol、アイデアは、C / C ++標準(c90、c11など)向けに記述されたコードを処理できるようにすることです。厳密に言えば、それは不可能です(私の2番目の不自然な例を参照)。コードはまだC90は、(のように構築扱いしようとする??'ので、私たちはと比較し、) cpp -ansi(のようなもの...これらおよびC99 / C11のために// xxx)、それゆえ我々はとの比較cpp(またはcpp -std=c11...)
ステファンChazelas

@zwol、私は少し明確にするためにテストケースを分割しました。トライグラフはまだC11にあるように見えるため、私の2番目のテストケースは標準Cではありません。
ステファンシャゼラス16

6

sed

更新

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

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

可能なすべてをサポート(複数行コメント、[またはand]の前のデータ、);

 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
-------------------
実行:
$ sed -f command.sed FILENAME

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

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

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

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

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

データの後に始まるコメントに対しては機能しません。proc print data 2nd /*another comment is here*/
たとえば

@mazs更新され、それをチェック
بارپابابا

これは、文字列リテラル内のコメントを処理しません。これは、SQLの機能に応じて実際に問題になる場合があります
-zwol

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

 proc print data=sashelp.cars;
 run;

 data abc;
 set xyz;
 run;

空白行がある場合は削除します:

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

編集-ステファンによる短いバージョン:

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

まあ、私はterdonに同意します:期待される出力を見てみましょう。
ハンスショウ16

ところで:「/ * foo * / run; / * bar * /」を含む単一行はどうなりますか?それは単に「実行」されるべきです。?
ハンスショウ16

すごい!その後、私のソリューションが動作します。欲張りでない「。+?」を使用していることに注意してください
ハンスショウ16

2
-0777短い方法として参照してくださいBEGIN{$/=undef}
ステファンシャゼル

1
おそらく ifの.*?代わりに有効なコメントもあります。.+?/**/
-ilkkachu

2

SEDコマンドを使用し、スクリプトを使用しないソリューション

はい、どうぞ:

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

NBこれは、インストールしない限り、OS Xでは機能しませんgnu-sed。ただし、Linux Distrosでは動作します。


1
-i出力を新しいファイルにリダイレクトする代わりに、ファイルをその場で編集するオプションを使用できます。または-i.bakファイルをバックアップする方がはるかに安全
Rahul

1
すべてのケースで機能しているわけではありません。同じ行にコメントを入れて、何が起こるか見てみましょう...例set xy \; / * test * / perlも簡単に解決できると思う。
ルチアーノアンドレスマティーニ

@Rahul正確に、言及してくれてありがとう。もっとシンプルにしたかっただけです。
-FarazX

同じ行のコメントに対して機能していないと言ってすみません。
ルチアーノアンドレスマティーニ

@LucianoAndressMartini今やっています!
FarazX

1

sed一度に1行で動作しますが、入力のコメントの一部は複数行にまたがっています。/unix//a/152389/90751に従って、最初に使用trして改行を他の文字に変えることができます。その後sed、入力を単一行として処理し、tr再度使用して改行を復元できます。

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

nullバイトを使用しましたが、入力ファイルに表示されない任意の文字を選択できます。

*正規表現では特別な意味を持つため\*、リテラルと一致するようにエスケープする必要があり*ます。

.*ある貪欲 -それはより多くのを含め、可能な限り長いテキスト、マッチする*/とし/*。つまり、最初のコメント、最後のコメント、およびその間のすべてを意味します。これを制限するに.*は、より厳密なパターンに置き換えます。コメントには、「*」ではないものを含めることができ、「*」の後に「/」ではないものを含めることができます。複数*のsの実行も考慮する必要があります。

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

これにより、複数行コメント内の改行が削除されます。

data1 /* multiline
comment */ data2

となります

data1  data2

これが望んでいたものでない場合sedは、改行の1つを保持するように指示できます。これは、一致する可能性のある改行置換文字を選択することを意味します。

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

特殊文字\f、および何にも一致しなかった可能性のある後方参照の使用は、すべてのsed実装で意図したとおりに動作することを保証されていません。(GNU sed 4.07および4.2.2で動作することを確認しました。)


それがどのように機能するかをmneに教えてください。tr '\ n' '\ 0' | sed -e 's、/ *([^ *] \ | * \ + [^ * /])** \ + / ,, g' test.sas | tr '\ 0' '\ n'と私は次のようになりました:/ *これは出力データを出力するためです* / data abcdf; cfgtrを設定します。走る; proc print data = sashelp.cars; 走る; データabc; xyzを設定します。走る;
シャリクアラム

@ShariqueAlam test.sasそこにパイプラインの途中に配置したので、そこsedから直接読み取りますtr。最初のパイプラインは効果がありません。使用する必要がありますcat test.sas | tr ...
-JigglyNaga

0

1行のsedを使用してコメントを削除します。

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

proc print data=sashelp.cars;
run;
data abc;
set xyz;
run;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.