sedで空のコメントを削除する方法は?

sedで空のコメントを削除する方法は?

次のように空のJavaコメントを削除したいと思います。

/**
*/

/*
 *
 *
 *
*/

sedで試しましたが、次のコマンドは空のコメントだけでなくすべてのコメントを削除しました。

sed -r "/^\s*\/\*+\s*/,/\s*\*+\/\s*/d"

\s\*+\s間に形状線がある範囲のみを削除するようにsedにどのように通知できますか?私が探していますhttp://www.grymoire.com/Unix/Sed.html#uh-29しかし、私はそこで解決策を見つけることができませんでした。

PS:次のテストファイルを作成しました。

/**
bla bla bla
*/

/*ba dff
 *dd fdf
 *d f
 *df df df
*/

/**
*/

/*
 *
 *
 *
*/

class Test
{
 some code...
}

最初の方法:

sed -n '/[^ \/\*]/p' /tmp/tmp

 bla bla bla
/*ba dff
 *dd fdf
 *d f
 *df df df
class Test
{
 some code...
}

コメントの1つの開始と終了が削除されました。

perl -0777 -pe 's,\s*/\*[*\s]*\*/\s*, ,gs' < /tmp/tmp

/**
bla bla bla
*/

/*ba dff
 *dd fdf
 *d f
 *df df df
*/  class Test
{
 some code...
}

最後のコメントはクラス定義と同じ行にあります。

warl0ckの方法:

$ removeemptycomments /tmp/tmp








class Test
{
 some code...
}

答え1

sed は一度に 1 行だけ処理します。代わりにPerlを使用してください。

perl -0777 -pe 's,\s*/\*[*\s]*\*/\s*, ,gs'

これは、空のコメントとその周囲のすべてのスペースを単一のスペースに変換します(必須、そうでない場合は別のスペースに置き換えますint/* */iinti。これは、連続した空のコメントがある場合は連続する空白があるため、次のように変更する必要があることを意味します。

perl -0777 -pe 's,\s*(?:/\*[*\s]*\*/\s*)+, ,gs'

これで、間隔を維持するには、実行する操作とコメントの配置方法によって異なります。コメントがどこにあってもコメントの後ろのインデントを維持したいのですが、まだ不要なスペースを圧縮したい場合は、次のことを試すことができます。

perl -0777 -pe 's,(\s*)(?:\s*/\*[*\s]*\*/)+(\s*\n|\s*),"$1$2"=~/\n/?"\n":" ",ges'

つまり、コメントの周囲に改行文字がある場合は、改行文字(およびコメントの後の改行文字の後の元のインデント)またはスペースに置き換えられます。

これは、他の正規表現エンジンとは異なり、Perl正規表現代替演算子が最長の一致を見つけることを試みず、代わりに一致があるまでシフトの各部分を順番に調べるため、Perlを使用して可能です。

文字列内で発生する可能性がある空のコメントを無視したい場合は、"/***/"特に二重引用符または一重引用符の中にある二重引用符をエスケープすることを検討する必要がある場合は、少し面倒になります。しかし、Perlの交代正規表現演算子は私たちを救い出します。

perl -0777 -pe 's,(\s*)(?:\s*/\*[*\s]*\*/)+(\s*\n|\s*)|(/\*.*?\*/|//.*?\n|"(?:\\.|.)*?"|'\''(?:\\.)?.*?'\''|.[^"/'\'']*),"$3"or"$1$2"=~/\n/?"\n":" ",ges'

アイデアは、正規表現がファイル全体と一致することです。ただし、この大きなシフトの代替方法では、次のように動作します。トークナイザー

デフォルトでは、ファイルを通過してトークンに分割します。テキストは、私たちが探している空のコメント、二重引用符で囲まれた文字列、一重引用符文字('\''または同じエスケープ文字を含む'\033')、または他のすべてのトークンのシーケンスとして扱われます。

上記のように、空白または改行で置き換える空のコメントタグを探しており、他のすべてのタグはそれ自体で置き換えられます。これで、次の入力を処理できるはずです。

/* comments with " unmatched quotes ' */ /* */
  f('"', "/***/" /***/, "\"", "/****/")

正しい。これで構文に慣れていないので、うまくいかないjavaコーナーケースがある可能性があるため、Javaの専門家がこれを改善できるようになります(例:Cでは、トライグラムやバックスラッシュを使用して改行をエスケープできることを考慮する必要があります)したがって、/*途中で壊れたaが見つからない可能性があります/\<LF>*。これはおそらくJavaでも同じかもしれないので、これを考慮してコードを改善することができます。

答え2

削除するのではなく、予想される内容を印刷してみてください。この場合、より簡単です。

sed -n '/[^ \/\*]/p' file

/、空白、または*以外の内容を含むすべての行を印刷しようとします。

答え3

sed '/\/\*/{:a;N;/\*\//!ba};/^\s*\/\*\+[*\s\n ]*\*\/\s*$/d'

どこ

/\/\*/{:a;N;/\*\//!ba}

すべてのコメント文字列を1つの文字列に追加

/^\s*\/\*\+[*\s\n ]*\*\/\s*$/d

コメントが空であることを確認し、空であれば削除します。

答え4

/*sedはこれを行うことができますが、複数行のコメントを識別するのは複雑です。特に、リテラル文字列やコメントに注意して正しく処理したい場合は、さらにそうです。*///

ソースファイルは通常メモリに完全に収まるほど小さいので、1行ずつ処理しても利点はありません。 PerlやPythonなどの言語を使用してファイル全体をメモリにロードし、部分的にトークン化します。これはテストされていないPerlプログラムです。

perl -0777 -ne '
    while ($_ ne "") {
        if (s~\A[^/"]+|\A\x27\\?.\x27|\A"(?:[^\\"]|\\.")~~) { print $&; } # not a comment
        elsif (s~\A//(.*)$~~m) { $c = $&; print $c if $1 =~ /\S/ } # // comment
        elsif (s~\A/\*(.*?)(\*/|\z)~~) { # /*comment*/
            $c = $&;
            if ($1 =~ /\A[^\n\t *]/ || !$2) {
                print $c; # non-empty or non-terminated comment
            } else {
                $c =~ s/[^\n]//g; # empty comment: retain the newlines
                print $c;
            }
        } else {s~\A.~~; print $&;}
    }

'

関連情報