2016-08-26 9 views
2

CSVファイルのデータを構造化配列に格納する方法を知りました。私はgetl​​ineのを使用する必要が実現すると、このようなこれまでのところ、私はこのコードが出ている:これは私のデータリーダーがstringstreamを持つ配列構造体にデータを正しく格納するにはどうすればよいですか?

struct csvData //creating a structure 
{ 
    string username; //creating a vector of strings called username 
    float gpa; //creating a vector of floats called gpa 
    int age; //creating a vector of ints called age 
}; 

で、データを格納する部分:これは私の構造体である

csvData arrayData[10]; 
string data; 
ifstream infile; //creating object with ifstream 
infile.open("datafile.csv"); //opening file 
if (infile.is_open()) //error check 

int i=0; 
while(getline(infile, data)); 
{ 
    stringstream ss(data); 
    ss >> arrayData[i].username; 
    ss >> arrayData[i].gpa; 
    ss >> arrayData[i].age; 
    i++; 
} 

さらに、これは私が情報をプリントアウトしようとしていた方法です。しかし

for (int z = 0; z<10; z++) 
    { 
     cout<<arrayData[z].username<<arrayData[z].gpa<<arrayData[z].age<<endl; 
    } 

、このコマンドを実行するとき、私は、乱数のように見えるもののCOUTを得る:

1.83751e-0383 03 4.2039e-0453 1.8368e-0383 07011688

私は、これは、配列が格納しないで実行する必要があると仮定変数が正しく、したがってランダムなメモリスロットを読み込んでいますが、わかりません。

最後に、私が読もうとしているCSVファイルは次のとおりです。

username,gpa,age 
Steven,3.2,20 
Will,3.4,19 
Ryan,3.6,19 
Tom,3,19 

答えて

3

実際に個々のフィールドに、単一の行を解析しようとするあなたの解析コードでは何もありません:

while(getline(infile, data)); 
{ 

は、これは正しくdata文字列に入力ファイルから1行を読み取ります。

Steven,3.2,20 

と個々にその文字列を区切る:

stringstream ss(data); 

ss >> arrayData[i].username; 
ss >> arrayData[i].gpa; 
ss >> arrayData[i].age; 

あなたは、これはあなたがあなたの質問に示したものと同様、カンマ区切り値の一行を取ることになっているかto explain to your rubber duckを試してみる必要があります値をカンマで区切ります。これを行う>>演算子については何もありません。 operator>>は、入力をカンマではなく空白で区切ります。あなたの疑惑は正しいです、入力を正しく解析していませんでした。

これは自分で行う必要がある作業です。私は、学習体験として、または宿題を自分で手作業で行うことを希望していると推測しています。さて、あなた自身でやってください。 dataには1行しかありません。 std::stringfind()メソッドまたはstd::find()から<algorithm>までの任意の数のツールを使用して、data文字列内の各コンマを見つけ、各コンマの間にある文字列の各部分を抽出します。次に、2つの数値フィールドを適切なデータ型に変換する必要があります。それで、それぞれをstd::istringstreamに入れ、operator>>を使用して数値型に変換します。

しかし、すべてのことを言って、この問題をすばやく解決するには、別の汚いトリックがあります。

Steven 3.2 20 

は、スペースでカンマを交換std::replace()で自明である、またはで:dataで元の行が

Steven,3.2,20 

あなたにそれを回す、スペースでカンマを交換されなければならないすべてが含まれていることを思い出してください小さなループ。次に、結果をstd::istringstreamに埋め込み、operator>>を使用して、既に書いたコードを使用して、個々の空白で区切られた値を離散変数に抽出することができます。

実際にあなたの宿題が割り当てられていた場合は、手入力でコンマ区切りの値を手動で解析して抽出するコードを記述することは、教師がダーティトリックアプローチ...

+0

私は試してきましたが、最初の文字列を解析しようとしていました。これは機能しません:while(getline(infile、data、 '、')) –

+0

ファイル内のすべての値の後にコンマが続くわけではありません。 3番目ごとに改行文字が続きます。そのため、ファイル内に複数の行があります。あなたが見ているように、プログラムはあなたがするべきことを正確に行い、あなたがしたいことはしません。あなたは次のカンマ文字まで読むように言った。それはそれが何をするつもりです。改行がある場合、プログラムは気にしませんが、コンマが見えるまで読み込むように指示されているので、次の行にカンマが表示されるまで読み込みを続け、前の行の最後の値、1つの文字列として。 –

+0

ねえ、私はデータファイルを解析しようとするとかなりのトラブルを抱えています。あなたが私にサンプルコードのヒントを与える方法はありますか?私は今5日間立ち往生しています... –

2

トン、素敵な試みと素敵な完全な質問

建設中。ここに答えがある:

1)あなたは、ループの後にセミコロンを持っている:

while(getline(infile, data)); 

は、それを削除します。

どのように私はそれを簡単に把握できましたか?

C02QT2UBFVH6-lm:~ gsamaras$ g++ -Wall main.cpp 
main.cpp:24:33: warning: while loop has empty body [-Wempty-body] 
    while(getline(infile, data)); 
           ^
main.cpp:24:33: note: put the semicolon on a separate line to silence this warning 
1 warning generated. 

実際には、あなたにも-Wallことなく、その警告を取得する必要がありますが、それを使用して入る、それはまた、あなたに良いようになります:私はこのように、有効なすべての警告をコンパイル! :)

2)次に、いくつかの要素を読みますが、10ではなく、なぜ10を印刷しますか?実際に読んだもの、つまりiの数だけ印刷してください。

配列の10要素をすべて印刷しようとすると、構造体の配列を初期化していないため、初期化されていない要素が表示されます。

さらに、datafile.csvの行数は10未満でした。そのため、配列の作成を開始しましたが、ファイルに行がないときに停止しました。その結果、配列の一部の要素(最後の6つの要素)の一部が未初期化のまま残っていました。

初期化されていないデータを印刷すると、未定義の動作、そのため、ガベージ値が表示されます。

3)また、この:

if (infile.is_open()) //error check 

は次のように書くことができます一緒にすべてを置く

if (!infile.is_open()) 
    cerr << "Error Message by Mr. Tom\n"; 

ss >> arrayData[i].username;が食べるので

はまだ動作しませんPete Beckerが言ったように、入力行全体と次の2つの抽出は失敗しますが、私はここに残します。他の人は同じ試みをしません!!!!!!!

#include <iostream> 
#include <fstream> 
#include <string> 
#include <sstream> 

using namespace std; 

struct csvData //creating a structure 
{ 
    string username; //creating a vector of strings called username 
    float gpa; //creating a vector of floats called gpa 
    int age; //creating a vector of ints called age 
}; 

int main() 
{ 
    csvData arrayData[10]; 
    string data; 
    ifstream infile; //creating object with ifstream 
    infile.open("datafile.csv"); //opening file 
    if (!infile.is_open()) { cerr << "File is not opened..\n"; } 

    int i=0; 
    while(getline(infile, data)) 
    { 
     stringstream ss(data); 
     ss >> arrayData[i].username; 
     ss >> arrayData[i].gpa; 
     ss >> arrayData[i].age; 
     i++; 
    } 

    for (int z = 0; z< i; z++) 
    { 
     cout<<arrayData[z].username<<arrayData[z].gpa<<arrayData[z].age<<endl; 
    } 

    return 0; 
} 

出力:

C02QT2UBFVH6-lm:~ gsamaras$ g++ -Wall main.cpp 
C02QT2UBFVH6-lm:~ gsamaras$ ./a.out 
username,gpa,age00 
Steven,3.2,2000 
Will,3.4,1900 
Ryan,3.6,1900 
Tom,3,1900 

しかし、今、それは動作しますが、数分待つが、なぜこの:

while(getline(infile, data)); 
{ 
    ... 
} 

はしませんでしたか?

ので、ループの後にセミコロンを置くことは、これに相当します

while() 
{ 
    ; 
} 

あなたはおそらくすでに一つだけの行でループを知っているように体が必要としないようので、中括弧。

ループの本体(つまり、一部はstd::stringstreamを使用していました)と思ったことは何ですか?

実行されました! しかし一度だけ!

あなたは、中括弧のペアだけが何かを意味していることが分かります。匿名のスコープ/ブロックです。

ので、この:あなたはあまりにも意図したとおりに

{ 
    stringstream ss(data); 
    ss >> arrayData[i].username; 
    ss >> arrayData[i].gpa; 
    ss >> arrayData[i].age; 
    i++; 
} 

は、whileループの一部ではなくて、そのいずれかで機能しました!

なぜそれが機能しましたか?あなたはループの前にiを宣言していたので! ;)

+0

これは、 'ss >> arrayData [i] .username;が入力行全体を奪い、次の2回の抽出が失敗するという中核の問題には対処していません。 –

+0

@PeteBeckerねえ、これまでに逃した!ありがとう、印刷は役に立たなかった。それに関するアイデア? – gsamaras

関連する問題