いい加減、stringstreamを覚えようという話

個人的に、プロコン用のコーディングではC言語系の入力が好きで、stream系は全く使っていなかったのだけど、ちょっと不便を感じることが多くなってきたので改心しようと思う。

例えば、次のような問題。具体的にはこういうの(http://www.deqnotes.net/acmicpc/p0017/ja)がある。

n個のデータセットがある。各データセットは改行で区切られている。各データセットは、半角スペースで区切られた整数を1行に並べた構成。並べられた整数の個数はデータセットごとに異なるかもしれない。このようなデータを読み込むにはどうすればよいか。

もしも各データセットごとに整数の個数が固定されていたら話は単純で、A[n_dataset][n_nums]みたいな配列を準備して各要素に対する入力をn_nums回やればいい。

でも、今回みたいに入力の個数が固定されない場合もある。こういう時、今までは凄く面倒なことをしていた。バッファを作って、スペースが出るまで1つづつ順番に読み込んでいってスペースがきたらatoi(buf)して・・とか、毎回やってると発狂しそうになるので簡単な方法を覚えることにした。

そこで、stringstream。
このエントリ(http://d.hatena.ne.jp/g940425/20110212/1297531253)を参考にした。
以下のような感じになる。

#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

int main() {
	ifstream fin;
	fin.open("input");
	//input
	/*
	2 3 4 
	1 43 21 777 1
	23 45
	23 345 54 0
	3
	0 98
	*/

	vector<vector<int> > v;
	while(true) {
		string str;
		getline(fin, str, '\n');
		if(str.empty()) break;
		stringstream ss(str); //stringstream
		int tmp; vector<int> vbuf;
		//very easy!!
		//----------------------------------
		while(! ss.eof()) {
			ss >> tmp;
			vbuf.push_back(tmp);
		}
		//----------------------------------
		v.push_back(vbuf);
	}
	fin.close();

	//output
	for(int i = 0; i < v.size(); i++) {
		for(int j = 0; j < v[i].size(); j++) {
			cout << v[i][j] << ' ';
		}
		cout << endl;
	}
	/*
	2 3 4 
	1 43 21 777 1 
	23 45 
	23 345 54 0 
	3 
	0 98 
	*/
}

stringstreamはスペースを無視するので、とてもお手軽である。

※こんなもの、例えばpythonならstr.split(delim)とか1行書くだけと思っても言ってはいけない
※具体例で出した問題は、各データセットの先頭に入力データの数がきているので、これを利用すればもっと楽に書ける