- 締切済み
固定幅フィールドのテキストデータをifstreamを使って読み込む方法
固定幅フィールドのテキストデータをifstreamを使って読み込む方法 について教えてください。 計算結果の出力ファイルに1行につき8カラム、20カラム、10カラムのデータがあるとします。 例えば 1.2345671.2345678912345678911.23456789 このデータ行には 1.234567(8カラム幅) 1.234567891234567891(20カラム幅) 1.23456789(10カラム幅) の3つの固定小数点の数字が書かれています。 上記例のように3つ(複数)の数字が必ずしもホワイトスペース区切りにはなっていないものとします。 これをC++標準ライブラリのifstream や stringstreamを用いて読み込む場合、どのような記述をしなければならないのでしょうか? たとえば、 int main(int argc, char** argv) { double data[3]; char buf[BUFSIZ]; ifstream ifs( argv[1] ); // argv[1] には上記データが書かれたファイル名が入っているとします。 stringstream str; while( !ifs.eof() ) { if( !ifs.getline( buf, BUFSIZ, '\n' ) ) break; str << buf; str >> setw(8) >> data[0] >> setw(20)>> data[1] >> setw(8) >> data[2]; } cout << data[0] << " " << data[1] << " " << data[2] << endl; return 0; } のような書き方だと、以下のように出力されてしまい、幅を指定しているsetw()が効いていません。 1.23457 0.234568 0.234568 恐らく、'.'がセパレータとして使われて読み込まれているものと思います。 sscanf( buf, "%8lf%20lf%10lf", &data[0], &data[1], &data[2] ); を使うしか方法が無いのでしょうか? 開発環境は ubuntu上のg++ 4.4.3 です。
- みんなの回答 (3)
- 専門家の回答
みんなの回答
- hidebun
- ベストアンサー率50% (92/181)
あー、すまん。おっしゃるとおり、setprecisionは出力方向に有効なのでした。 ifstreamにfscanfの書式指定読み込みのようなI/Fはなかったと思う。 fscanfを使わない場合は、自分で処理を書くしかないかなぁ。 今回のケースなら、書いてもしれているので、それがよいかと思います。
- επιστημη(@episteme)
- ベストアンサー率46% (546/1184)
たとえばこんなやりかたが。 #include <iostream> #include <sstream> #include <string> using namespace std; template<typename T> void get_value(const string& input, T& v) { istringstream stream(input); stream >> v; } int main() { // ↓ファイルから読み出された一行 string input = "1.2345672.3456789012345678903.45678901"; double value; // 8, 20, 10 に区切ってdouble値を読み出す get_value(input.substr(0,8),value); cout << value << endl; get_value(input.substr(0+8,20),value); cout << value << endl; get_value(input.substr(0+8+20,10),value); cout << value << endl; }
お礼
回答ありがとうございました。 文字列側で区切っておけば良いわけですね。 標準C++ライブラリの解説本を使って勉強し始めたのですが、Stringコンテナにsubstr()なる メンバー関数があることを、epistemeさんの回答で気付きました。 参考にさせて頂きます。
- hidebun
- ベストアンサー率50% (92/181)
setwに加え、setprecisionも使おう。
補足
hidebunさんへ str >> setw(8) >> setprecision(6) >> data[0] >> setw(20)>> setprecision(18)>> data[1] >> setw(10) >> setprecision(8) >> data[2]; のような書き方をしても全く効果ありません。 解説書によると setw()は入出力、setprecision()は出力のみのマニピュレータとなっています。 P.S. 質問の記述に誤りがありました。 リスト中に3つあるsetw()の内、最後のsetw(8)はsetw(10)です。 (どちらにしても、効いていませんが・・・・)
お礼
書式指定入力を行う場合には、Cのライブラリを使うしかなさそうですね。 今までC++の機能はclassの関係のみ使用して、ライブラリ関係は全てCのライブラリ関数を 使用した20年以上前?の状態でプログラミングしていました。 最近のネット上のサンプルコードを見ると、template<>, ~~stream などが満載のコード ばかりで、目で追うこともできなくなっていたので、本を1冊購入して勉強し始めたとこです。 「C++標準ライブライリ」とは言っても、Cの標準ライブライリを完全に置き換えるとこまでは意図していないのですね。