sedを使ってコメント行を削除する


sedを使ってコメント行を削除する

今回削除対象に選ばれた記号の皆さんです。

  • 「#」
  • 「//」
  • 「/**/」

では、早速始めてましょう。

「#」と「//」を削除

まずは簡単そうな「#」と「//」で始まる行を削除してみます。
特に難しいことはしていないので、ちゃちゃっと書いていきます。

cat <<EOF| sed -e '/^\/\//d' -e '/^\#/d'

ヒアドキュメントを利用しているので対話形式で入力していきます。
今回はコメントされているテキストを2つとコメントされていないテキストを1つ用意して試してみます。
入力する単語は以下です。

aaa
// bbb
# ccc

すると、「// bbb」と「# ccc」が除外され、「aaa」のみが出力されます。

aaa

最終的なターミナルは以下のようになります。(mac+zshでカスタマイズしているのでプロンプトが変かもですが)

cat <<EOF| sed -e '/^\/\//d' -e '/^\#/d'
pipe heredoc> aaa
pipe heredoc> // bbb
pipe heredoc> # ccc
pipe heredoc> EOF
aaa

解説

 sed -e '/^\/\//d' -e '/^\#/d'にてコメントを削除しています。今回のように削除対象が複数存在する場合、sedでは-eオプションを複数作ることで実現できます。したがって、このコマンドは「行頭が「#」または「//」で始まる行を削除する」と表現できます。

「/**/」を削除

これはちょっと難しそうですねー。でも大丈夫です。これもsedで解決できます。
ということで書いてみます。

cat <<EOF| sed -e '/\/\*/,/\*\// s/.*//' | grep -v '^$'

ヒアドキュメントに以下のように入力します。

aaa
/* bbb
ccc
*/
/* 
ddd */
eee

すると、「// bbb」と「# ccc」が除外され、「aaa」のみが出力されます。

aaa
eee

最終的なターミナルは以下のようになります。

cat <<EOF| sed -e '/\/\*/,/\*\// s/.*//' | grep -v '^$'
pipe pipe heredoc> aaa
pipe pipe heredoc> /* bbb
pipe pipe heredoc> ccc
pipe pipe heredoc> */
pipe pipe heredoc> /*
pipe pipe heredoc> ddd */
pipe pipe heredoc> eee
pipe pipe heredoc> EOF
aaa
eee

解説

 恐らくお気づきだと思いますが、sed -e '/\/\*/,/\*\// s/.*//'の部分で除外しています。sedでは開始地点と終了地点のテキストを指定し、その範囲を置換することができます。ここですね'/\/\*/,/\*\//。書き方としては/START_TEXT/,/END_TEXTのように記述します。対象としている記号がエスケープ文字を必要とするので読みづらさMAXですが・・・。
 次に範囲をどのようなルールで置換するのかを宣言します。ここですねs/.*//。今回は範囲内の全ての文字列を削除する命令をセットしました。
 最後に出力結果をgrepに渡し空の行を除外しています。本来であれば、sedの/[削除したい文字列やパターン]/dにて対応できればgrepを使う必要はないのですが、どうも範囲指定を利用する場合使えないようなので渋々この形になりました。

おまけ

 コメント行や空行を除いた純粋なソースコードの行数を知りたいという動機からこの記事を書いたわけです。なので、インデントを考慮して行数を出す必要がありました。ただ、今回僕が知りたかったのはソースコードからコメントなどを排除した形にしたい(つまり整形)というわけではなく、ソースコードの行数だけだったので、コメントの行を炙り出す前に事前処理としてインデントを排除することを選択しました。ここでは詳しい解説は行いませんが、最終的なターミナルのみ載せておきます。

echo 'aaa\n\tbbb\n ccc\n\t ddd' | gsed -e 's/[ \t]*//' | sed -e '/^\/\//d' -e '/^\#/d' -e '/\/\*/,/\*\// s/.*//' | grep -v '^$'
aaa
bbb
ccc
ddd

 ヒアドキュメントにて「空白」と「タブ」を入れると出力がおかしくなるのでechoで対応しています。また、macのsed(BSD sed)では「\t」でタブを表現できないのでその部分のみgsed(GNU sed)を利用しています。ちなみに、macのsedでタブを表現する際には[:cntrl:]を使って表現できます。

参考サイト

sedでこういう時はどう書く? - Qiita
BSD(Mac)のsedでのタブ文字を変換する3つの方法
ヒアドキュメントをパイプで渡す時の注意点 | ライカ犬は今何処