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