C++形式のコメントを取り除く « L.T.SOFTWARE

C++形式のコメントを取り除く


C++形式のコメント「//~~」や「/*~~*/」を取り除く必要があったので書いてみました。
単純に正規表現だと、文字列定数内までコメント扱いしてしまうので自前で。
本当はyacc/lexとかboost::spiritとか使ったほうが確実で堅実なんだろうけど、
そこまで大事にしたくないな。関数一つだけで何とかしたいなって場合にオススメ。

void removeComments( std::string &str ) {
	enum COMMENT_PARSE_STATE {
		NORMAL,
		SLASH_BEGIN,
		IN_SINGLE_QUOTE,
		IN_DOUBLE_QUOTE,
		REMOVE_TO_END_LINE,
		MULTI_LINE_COMMENT,
		SINGLE_LINE_COMMENT,
	};

	COMMENT_PARSE_STATE state = NORMAL;
	std::size_t begin = std::string::npos;
	for(std::size_t i = 0, iEnd = str.size();i<iEnd; ){
		char c = str[i];
		switch(state){
			case NORMAL:{
				switch( c ){
					case '\'':
						state = IN_SINGLE_QUOTE;
						break;
					case '"':
						state = IN_DOUBLE_QUOTE;
						break;
					case '/':{
						state = SLASH_BEGIN;
						begin = i;
						break;
					}
				}
				++i;
				break;
			}
			case SLASH_BEGIN:{
				switch(c){
					case '/':{
						state = SINGLE_LINE_COMMENT;
						break;
					}
					case '*':{
						/*で複数行コメントなので続く*/
						state = MULTI_LINE_COMMENT;
						break;
					}
					default:
						state = NORMAL;
						break;
				}
				++i;
				break;
			}
			case SINGLE_LINE_COMMENT:{
				if( c == '\r' || c == '\n'){
					//ここまで全部コメント
					std::size_t lenComment = i - begin;
					str.erase(begin,lenComment);
					i = begin + 1;//改行の次を指す
					iEnd -= lenComment;
					state = NORMAL;
				} else {
					++i;
				}
				break;
			}
			case MULTI_LINE_COMMENT:{
				if( c == '/' && str[i-1] == '*' ){
					std::size_t lenComment = i - begin + 1;//iの位置の文字スラッシュも削除する
					//複数行コメント終了
					str.erase( begin , lenComment );
					iEnd -= lenComment;
					i = begin;//beginの位置まで削除したので、ポイントをその位置に戻す
					state = NORMAL;
				} else if( c == '\n' || c == '\r'){
					//改行の手前まで削除して、改行はスキップする
					std::size_t lenComment = i - begin;//改行手前までの文字列を削除する
					if( lenComment > 0 ){
						str.erase(begin, lenComment);
						iEnd -= lenComment;
					}
					++begin;
					i = begin;//beginの位置+1(改行)まで削除したので、ポイントをその位置に戻す
				} else {
					++i;//削除される文字なのでスキップ
				}
				break;
			}

			case IN_SINGLE_QUOTE:{
				//シングルクォートが出てきて、直前が\じゃないならシングルクォート終了
				if( c == '\'' && str[i-1] != '\\' ){
					state = NORMAL;
				} else if( c == '\r' || c == '\n' ){
					state == NORMAL;
				}
				++i;
				break;
			}

			case IN_DOUBLE_QUOTE:{
				//ダブルクォートが出てきて、直前が\じゃないならダブルクォート終了
				if( c == '\"' && str[i-1] != '\\' ){
					state = NORMAL;
				} else if( c == '\r' || c == '\n' ){
					state == NORMAL;
				}
				++i;
				break;
			}
		}
	}

	if( state == SINGLE_LINE_COMMENT || state == MULTI_LINE_COMMENT ){
		//コメントが尻切れで終わっているので、文末まで全部コメントと判断するbeginから先全部削除する
		str.erase(begin);
	}
}



コメントをどうぞ