プログラミング関係の話題を取り上げるとき,しばしばサンプルコードを載せることがある訳ですが,このときに問題になるのがタグ文字などの特殊文字.具体的には,“<”,“>”,“&”,“"”はそれぞれ“<”,“>”,“&”,“"”に変換する必要があります.これを手作業で行うのはさすがに面倒なので,一括変換してくれるプログラムが欲しくなります.私は,S34:Making of C++ Technical Documentsで紹介されているプログラムを利用しています.
さて,この変換プログラムは以下のようになります.
#include <iostream> #include <iterator> #include <string> #include <map> template <class InIter, class OutIter> OutIter src2html(InIter first, InIter last, OutIter result) { typedef InIter input_iterator; typedef typename input_iterator::char_type char_type; typedef typename input_iterator::traits_type traits_type; typedef std::basic_string<char_type, traits_type> string_type; typedef std::map<char_type, string_type> escmap; escmap esc; esc['&'] = "&"; esc['"'] = """; esc['<'] = "<"; esc['>'] = ">"; while (first != last) { char_type c = *first++; typename escmap::iterator pos = esc.find(c); if (pos != esc.end()) { result = std::copy(pos->second.begin(), pos->second.end(), result); } else *result++ = c; } return result; } int main(int argc, char* argv[]) { std::ostreambuf_iterator<char> result(std::cout); std::istreambuf_iterator<char> input(std::cin); std::istreambuf_iterator<char> last; src2html(input, last, result); return 0; }
標準入力から一文字ずつ読み取り,変換しなければならない文字なら対応する文字列を出力し,それ以外の文字はそのまま出力するという流れになっています.ここで面白いのが,src2htmlはイテレータで受け取っているという事.このプログラム,メイン関数を以下のように書き換えても問題なく動作します.
int main(int argc, char* argv[]) { std::ostreambuf_iterator<char> result(std::cout); std::string s = "#include <iostream>"; src2html(s.begin(), s.end(), result); return 0; }
つまり,制御関数(src2html)を実装する際には,イテレータを用いることによって,メイン関数からの入力(文字列が来るのか,ストリームから読み取らなければならないのか)を意識せずに実装することができます(実際,algorithmヘッダファイルで提供される関数もこの形で実装されています).
それにしても,istreambuf_iterator/ostreambuf_iteratorというクラスが用意されていることは知りませんでした.C++ ライブラリ クイックリファレンスによると,
istreambuf_iteratorクラステンプレートは、ストリームバッファから文字を読み取るための入力反復子として、ストリームバッファオブジェクト(basic_streambufのインスタンス)をラッピングする。
とのことですが,なるほどやり易いようにいろいろと用意されているのですね.C++もまだまだ知らないことが多いです.そのうち,リファレンスも一度全部目を通してみようかと思います.