0

ファイルからのデータは次のようになっているため、1行目は名前(最初の最後)、次の行はスコア(スコア1スコア2 ....スコア5)などです...だから、名前にはgetl​​ine、名前には>>が必要だと思いますスコア

データファイルの例

David Beckham
80 90 100 20 50
Ronaldinho Gaucho
99 80 100 20 60
....

まず、私は構造を持っています

struct Player {
string name;
int score[5];
} player[size]

ファイルからデータを読み込む場合

int i = 0;
while(!file.eof())
    {
        for (int j = 0; j < 2; j++) //read each 2 two lines
        {               
            if(j==0) // name
            {               
                getline(file, player[i].name);  
            }
                        else if(j==1) // score
            {
                for(int k=0; k<5; k++) file >> player[i].grade[k];
            }
                }
         i++; //move to next player
    }

問題は、(最初​​のプレーヤーの)すべてのスコアを読み取った後、次の名前を読み続けるために次の行に移動しないように見えることです。私のコードを修正するための提案や、これを行うための新しいアイデアはありますか?

4

2 に答える 2

4

最後のスコアを読み取った後、改行はまだ入力バッファーにあります。それをスキップする必要があります。そんなときignoreに便利な機能です。

getline(file, player[i].name);
for (int k = 0; k < 5; ++k)
  file >> player[i].grade[k];
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

必要に応じてエラーを確認します。>>演算子、getline、およびすべてはignore、成功または失敗を確認できるストリーム参照を返します。


j各反復はまったく異なることを行うため、そのループは必要ありません。j=0上記のコードのように、ケースの直後にケースを記述しj=1、ループを取り除きます。(そしてj、ループ内で決して 2 に等しくならないことに注意してください。とにかく、あなたの条件は間違っていました。)

于 2012-06-14T18:40:42.737 に答える
1

あなたの主な問題は、ストリームから直接 >> で整数を読み取っていることです。これをストリームからの文字列の読み取りと組み合わせることは、悪い考えです。文字列を読み取ると改行が削除されますが、>> で読み取っても改行は削除されません。

2 つの形式を混在させないことをお勧めします。常に >> を使用するか、常に getline() を使用してください。注: 私は最高と言っているのではなく、最も簡単だと言っています。トレードオフと、使用方法の違いを補う方法を理解すれば、それらを一緒に使用できます。

したがって、数値の行を文字列に読み取ってから、文字列を解析する方が簡単です。

std::string  lineOfNumbers;
std::getline(file, lineOfNumbers);

// Now you have read all the numbers and the new line.
std::stringstream streamOfNumbers(lineOfNumbers);
while(streamOfNumbers >> value)
{
    // Do something with number.
}

ほとんどの場合、次の使用は間違っています。

while(!file.eof())

これは、eof を過ぎて読み取るまで EOF フラグが設定されないためです。最後の読み取りは、eof までではなく、eof まで読み取ることに注意してください。したがって、利用可能なデータがなくてもループに入ります。

標準的なパターンは次のとおりです。

while(file >> object)
{
   // Action
}

これを念頭に置いて、必要なすべての情報 (つまり 2 行) を表すクラスを定義します。シンプルなバージョンは

class TwoLineReader
{
   public:
     std::string line1;
     std::string line2;
};
std::istream& operator>>(std::istream& stream, TowLineReader& record)
{
    std::getline(stream, record.line1);
    std::getline(stream, record.line2);
    return stream;
}

TowLineReader   obj;
while(file >> obj)
{
     // Do stuff
}

行を読むだけなら、これで問題ありません。
しかし、データには構造があるように見えます。したがって、データを表すクラスを作成し、データをその構造に直接読み込みます。だから、これは私がすることです。また、while() ループをアルゴリズムに置き換えます。

ヘッダー

#include <algorithm>
#include <iterator>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

/*
 * Example Data

David Beckham
80 90 100 20 50
Ronaldinho Gaucho
99 80 100 20 60
 */

クラス:

class Player
{
    std::string         name;
    std::vector<int>    goals;

    // Stream operator that reads a platers name and his goals.
    friend std::istream& operator>>(std::istream& stream, Player& record)
    {   
        // Read the name
        std::getline(stream, record.name);

        // Read the line of goals.
        // Copies the data into goals.
        std::string scores;
        std::getline(stream, scores);

        // std::copy replaces a while loop that pushes each number into the vector.
        std::stringstream scorestream(scores);
        std::copy( std::istream_iterator<int>(scorestream), 
                   std::istream_iterator<int>(), 
                   std::back_inserter(record.goals));

        return stream;
    }   
};

使用法:

int main()
{

    std::ifstream   dataFile("data");
    std::vector<Player>   players;

    // Copy all players into a vetor
    std::copy( std::istream_iterator<Player>(dataFile), 
               std::istream_iterator<Player>(), 
               std::back_inserter(players));
}
于 2012-06-14T19:22:12.140 に答える