CodeIQ:ソースコードからコメントを抽出しよう

私自身が表題の問題を解いた時のプログラムについて解説します。
問題の詳細は「ソースコードからコメントを抽出しよう」(CodeIQ)を参照してください。

問題の概要

問題を引用します。
あなたはソースコードからドキュメントを生成するツールの開発を任されており、まず規定の文法で記述されたコメントの内容を抽出するプログラムを作ることにしました。

求められるプログラムの前提条件は、以下の通りとなります。

標準入力から、ASCII文字で構成されたソースコードが送られる
ただしソースコード内の制御文字に関しては、改行コード(LF)のみとする
ソースコードは、1行80文字以下、100行以下とし、改行コード(LF)で行が区切られるものとする
コメントの内容は、"//"から改行コード、あるいは"/*"と"*/"で囲まれた間の文字列を指し、"//" "/*" "*/" 自体は含まれない
"/*"と"*/"で囲まれた間の文字列は複数行、つまり改行コードを含むケースも想定すること
コメント文がネスト(入れ子)、また正しく"/*"から始まっていない、もしくは"*/"で閉じられていないケースは考慮しなくてよい
抽出したコメントの内容を、すべて標準出力に返すこと

以下、入出力例になります。
(引用者注:スペースがわかりにくいので入出力文字列の背景色を薄い灰色にしました)

入力 出力
// C++ sample
#include <iostream>
 C++ sample
/* C++ sample */
#include <iostream> // test
 C++ sample  test
/*
  C-Lang sample
*/
// test
#include <stdio.h>

 C-Lang sample
 test

ソースコード内のコメントからドキュメントを生成するツールはDoxygenなど有名なものも存在します。
ただ、こうした処理を自前で書けるようになると、SQLにコメントルールを設けたうえで、テーブル設計書を自動生成するといった、既存ツールでは対応できない応用が可能になります。
是非挑戦してみてくださいね。

【問題】
標準入力から、何らかのソースコードが送られます。
このソースコードから、規定のルールで記述されたコメントの内容のみを抽出し、その結果を標準出力に返してください。

私のプログラム

Rubyで解答しています。

#!/usr/bin/ruby

# main
comments = ""
multi_line = false

while line = gets
	if line =~ /\/\// then
		comments += line.chomp[line.index("//")+2..-1]
	elsif line =~ /\/\*/ && line =~ /\*\// then
		comments += line[line.index("/*")+2...line.index("*/")]
	elsif line =~ /\/\*/ then
		multi_line = true
		comments += line.chomp[line.index("/*")+2..-1]
	elsif line =~ /\*\// then
		comments += line[0...line.index("*/")]
		multi_line = false
	elsif multi_line then
		comments += line
	end
end

printf("%s", comments)

解説

特に難しいわけではありません。
ただし、仕様の曖昧さとHTML上でスペースがわかりにくいことにイライラさせられます。

考え方

1行に2つのコメントがあるような場合は無視しました。
下のようなコメントも文法上問題ないのですが、考慮していないということです。
/* Comment1 */ /* Comemnt2 */
#include <stdio.h>
int main(void){
	printf("Hello World!\n"); /* Hello */ //World
}

前述の前提があるので1行単位で処理します。
"//"で始まっている場合は"//"の次から最後の文字(改行コード)の1文字前までをコメントとします。
1行の間に"/*"と"*/"がある場合はその間をコメントとします。
"/*"が存在し、同一行に"*/"がない場合は複数行コメントと判断し、"/*"から改行の1文字前まで出力し(例では改行も出力することになっていますがテストケースでは"/*"と同一行にある改行は出力しないようになっていました)、"*/"が現れるまでをコメントとして出力し続けます。

main

考え方に書いた通りの実装です。
複数行コメントの場合はmulti_line変数をフラグとして使用しています。

雑感

問題を見た瞬間、出力フォーマットをテストケースに一致させるのにイライラさせられるだろうな、と思いましたがその通りでした。
もう一つ、この問題の通り実装したコメント抽出で抽出したコメントはドキュメントとして利用価値がないのもどうかと思いました。例えば次のようなコメントの場合です。
// test
/*
  C-Lang sample
*/
#include <stdio.h>

出力結果は次のようになります。
 test  C-Lang sample
わざわざ分けて書いたコメントが1行に出力されてしまいます。使えませんよね。
実用プログラムではなく問題だから構わないのですが……。