torutkのブログ

ソフトウェア・エンジニアのブログ

std::stringをSTLアルゴリズムで使う

C++である文字列からその一部分を抜き出したいとき、std::stringのメンバ関数を見ると、何文字目、何文字分といった数値指定をするAPIが多く、C言語的です。(例:findは見つかった文字が何バイト目にあるかを数値で返却)

そこで、STLアルゴリズムが使えると便利ではないかと思い調べてみました。

using std::string;
// 処理対象文字列textの設定
string text = "January, Feburary, (March), Aplil";
// 文字列textから、開き括弧の位置を探しその位置をiteratorで取得
string::iterator openbracket = std::find(text.begin(), text.end(), '(');
if (openbracket == text.end()) {
    std::cerr << "open bracket not found" << std::endl;
    retrun;
}
// 文字列textから、閉じ括弧の位置を探しその位置をiteratorで取得
string::iterator closebracket = std::find(openbracket, text.end(), ')');
if (closebracket == text.end()) {
    std::cerr << "close bracket not found" << std::endl;
    return;
}

と文字列中から開き括弧、閉じ括弧を検索してそれぞれの反復子を取得します。
次に、2つの反復子で指定された範囲を別な文字列として抜粋します。

  • 最初は、std::string自体に用意された手段です。
// イテレータで指定した範囲から新たな文字列を生成
string subset1(openbracket+1, closebracket);
// イテレータで指定した範囲を文字列に適用
string subset2;
subset2.assign(openbracket+1, closebracket);
string subset;
std::copy(openbracket+1, closebracket, subset.begin());

copyアルゴリズムで、イテレータ範囲を文字列subsetの頭から入れたかったのですが、コピーされず、subsetは空文字列のままです。

string subset;
std::insert_iterator<string> insit(subset, subset.begin());
std::copy(openbracket+1, closebracket, insit);
string subset;
std::copy(openbracket+1, closebracket, std::inserter(subtext, subtext.begin());

insert_iteratorを返す関数std::inserterを使用したものです。

      • コピーする文字列数に合わせて文字列のサイズを確保しておく
string subset(closebracket - openbracket - 1, '#');
std::copy(openbracket+1, closebracket, subset.begin());

stringにはサイズだけ指定したコンストラクタがないので、サイズとダミーの文字を指定しておきます。
数値の-1,+1が非常に間違いやすい(バグの原因)です。(現に最初間違えてました)

2009/1/18修正

eldeshさんコメントを受けて、サンプルコードを修正しました。