ストリームバッファのイテレータ
プログラミング関係の話題を取り上げるとき,しばしばサンプルコードを載せることがある訳ですが, このときに問題になるのがタグ文字などの特殊文字.具体的には,“<”,“>”,“&”, “"”はそれぞれ“<”,“>”,“&”,“"”に変換する必要があります. これを手作業で行うのはさすがに面倒なので,一括変換してくれるプログラムが欲しくなります. 私は,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++ ライブラリ クイックリファレンス p.261)
とのことですが,なるほどやり易いようにいろいろと用意されているのですね.