前々回のプログラムを、今回はもうちょっとまともに書き直して見ます。
その時、ちょっと興味のあった boost::iostreams::output_filter
の機能を使って試してみましょうかね。
では、さっそく:
#include <iostream> #include <string> #include <boost/xpressive/xpressive.hpp> #include <boost/iostreams/filtering_stream.hpp> #include <boost/iostreams/concepts.hpp> #include <boost/iostreams/operations.hpp> #include <boost/iostreams/copy.hpp> using namespace std; using namespace boost::xpressive; using namespace boost::iostreams; // HTML文字参照を行うフィルタ #include <map> class char_ref : public output_filter { public: typedef map< int, const char* > list_type; char_ref( const list_type& ls ) : ref_list(ls) { } // 出力本体 template<typename Sink> bool put( Sink& snk, int c ) { list_type::const_iterator ite = ref_list.find(c); if( ite == ref_list.end() ) { // 文字参照リストに含まれていなかったら、そのまま出力 return boost::iostreams::put( snk, c ); } else { // 文字参照リストに含まれていたら、その文字列を出力 const char* p = (*ite).second; while( *p ) { boost::iostreams::put( snk, *(p++) ); } return true; } } // 文字参照リスト const list_type& ref_list; }; ostream& cpp_decoration( ostream& os, string src /* 明示的にコピーするの面倒なので、最初から値で */ ) { sregex c_ = ("/*" >> -*_ >> "*/") | // C コメント ("//" >> *(~_n) ); // C++ コメント sregex comment = c_ >> *( *space >> c_ ); // クォートされた文字列。( '&' >> -*_ >> ';' ) は「文字参照一文字」 sregex quoted = ( ~after('\\') >> '"' >> -*_ >> ~after('\\') >> *(as_xpr("\\\\")) >> '"') | ( ~after('\\') >> '\'' >> !as_xpr('\\') >> ( _ | '&' >> -*_ >> ';' ) >> '\'' ); smatch m; // コメントか、文字列(最初に出てきたほう)を検索 while( regex_search( src, m, ( quoted | comment ) ) ) { // とりあえず、出現までは普通に流して os << m.prefix().str(); // マッチの最初の文字で、どっちかを判定 if( m.str()[0] == '/' ) { // コメント os << "<span class=comment>" << m.str() << "</span>"; } else { // 文字列 os << "<span class=quoted>" << m.str() << "</span>"; } // 残りの文字列を、改めて検索対象に src = m.suffix().str(); } // 見つからなかったので、そのまま出力 return os << src; } int main() { ostringstream buf; filtering_ostream sink; // 文字参照リストを作って char_ref::list_type ls; // 格納 ls['&'] = "&"; ls['<'] = "<"; ls['>'] = ">"; sink.push( char_ref(ls) ); sink.push( buf ); // 折角なので boost で copy( cin, sink ); cpp_decoration( cout, buf.str() ); return 0; }
こんな感じで、どうでしょうか。
解説は・・・面倒なので気が向いたら今度。