stringstreamを使った入出力の処理

あんまよくわかんないからといって無視してきたstringstreamクラスが、調べてみるとこれがなかなか使えそうだったので覚書。
strstreamではなくstringstreamの方です。もっといえばヘッダじゃなくてヘッダで読み込む奴の方です。
いったいなんでこんなに警告吐かれんのとか思ってたら単なる見間違いとか……一体俺はなにやってんのかと......

・文字列以外の変数を文字列にまとめる
まあ普通の使い方?出力が決まった形でなければならないときとかに。日付とか。

int n;
double d;
char c;
ostringstream os;

os<<"int :"<<n<<endl<<"double :"<<d<<endl<<"char :"<<c<<endl;
cout<<os.str();

C++にはないsplit()関数の代わり
これがstringstream使えるねと言う主な理由。
例えば、コンマ区切りの整数の読み方を以前記事にしましたが、あれがもっと効率的にできます。

string str;
int temp;
vector<int> v;

getline(cin,str);
stringstream ss(str);

while(!ss.eof()){
	ss>>temp;
	v.push_back(temp);
	ss.ignore();
}

この方法のちょっといいところは、
「整数読みこみ → 区切り文字読み飛ばし」
のループなので、区切り文字がスペースだったりドットだったり(セミ)コロンだったりした時も全く同じコードで読み込めること。スペースのときは読み込むときに↑のようにgetline(cin,str)で読まないと文字列に読み込む時点で切れます。

また、たとえば

NAME:TARO,ID:123
NAME:MARY,ID:999

のように入力形式が多少複雑でも、

int m;
string str,name;
int id;
vector<pair<int,string> > v;

stringstream ss;

while(cin>>str){
	m = str.find("NAME:");str.replace(m,5,"");
	m = str.find(",ID:");str.replace(m,4," ");
	
	ss.clear();
	ss.str(str);
	ss>>name>>id;
	v.push_back(pair<int,string>(id,name));
}

とすればできます。
要はスペース区切りの文字列に変換した後読み込めばOK。

あ、あと上のプログラムについて一つ注意。
ss.clear()はストリームの状態をクリアする関数で、ストリームをクリアしないとポインタが前の"TARO 123"を指したまんまになってしまいます。
ちなみにostringstreamで内容を一回クリアしたいときはos.clear()でなくos.str("")としなければなりません。clear()つかってもこっちはフラグの状態ぐらいしかクリアされません。


と、このように、stringstreamをうまく使えれば、入力や出力が多少扱いづらくてもなんとかなりますよっと。そういうわけでした。

まあ、何故こんな記事をいきなり書いたかというと、プログラミングコンテストの問題解いててアルゴリズムはわかっても入出力まわりの細かいとこで苦戦するとめっちゃイライラしますよね(;´Д`)ということです。はい。ではまたorz