プロが教えるわが家の防犯対策術!

固定幅フィールドのテキストデータを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 です。

A 回答 (3件)

あー、すまん。

おっしゃるとおり、setprecisionは出力方向に有効なのでした。
ifstreamにfscanfの書式指定読み込みのようなI/Fはなかったと思う。
fscanfを使わない場合は、自分で処理を書くしかないかなぁ。
今回のケースなら、書いてもしれているので、それがよいかと思います。
    • good
    • 0
この回答へのお礼

書式指定入力を行う場合には、Cのライブラリを使うしかなさそうですね。

今までC++の機能はclassの関係のみ使用して、ライブラリ関係は全てCのライブラリ関数を
使用した20年以上前?の状態でプログラミングしていました。
 最近のネット上のサンプルコードを見ると、template<>, ~~stream などが満載のコード
ばかりで、目で追うこともできなくなっていたので、本を1冊購入して勉強し始めたとこです。 「C++標準ライブライリ」とは言っても、Cの標準ライブライリを完全に置き換えるとこまでは意図していないのですね。

お礼日時:2010/08/09 07:08

たとえばこんなやりかたが。



#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;
}
    • good
    • 0
この回答へのお礼

回答ありがとうございました。

文字列側で区切っておけば良いわけですね。
標準C++ライブラリの解説本を使って勉強し始めたのですが、Stringコンテナにsubstr()なる
メンバー関数があることを、epistemeさんの回答で気付きました。
参考にさせて頂きます。

お礼日時:2010/08/08 20:59

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)です。
(どちらにしても、効いていませんが・・・・)

補足日時:2010/08/08 21:07
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!