我想知道如何将CSV文件中的数据存储到结构化数组中。我意识到我需要使用getline等,到目前为止我已经提出了这个代码:
这是我的结构:
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
答案 0 :(得分:3)
您的解析代码中没有任何内容实际上尝试将单行解析为单个字段:
while(getline(infile, data));
{
这正确地从输入文件中读取一行到data
字符串。
stringstream ss(data);
ss >> arrayData[i].username;
ss >> arrayData[i].gpa;
ss >> arrayData[i].age;
你需要尝试to explain to your rubber duck这应该如何采用一行逗号分隔值,就像你在问题中展示的那样:
Steven,3.2,20
并用逗号将该字符串分隔成单个值。这样做的>>
运算符没有任何意义。 operator>>
使用空格而不是逗号分隔输入。您的怀疑是正确的,您没有正确解析输入。
这是你必须自己完成的任务。我假设您希望,作为一种学习经历,或作为家庭作业,自己手动完成这项工作。好吧,那么,自己动手吧。您在data
中有一行。使用C ++为您提供的任意数量的工具:std::string
的{{1}}方法或find()
的{{1}}(),以查找std::find
中的每个逗号{1}}字符串,然后提取每个逗号之间的字符串的每个单独部分。然后,您仍然需要将两个数字字段转换为适当的数据类型。当你将每一个放入<algorithm>
时,并使用data
将它们转换为数字类型。
但是,尽管如此,还有另一种肮脏的技巧,可以快速解决这个问题。回想一下std::istringstream
中的原始行包含
operator>>
您所要做的就是用空格替换逗号,将其变为:
data
使用 Steven,3.2,20
或使用小循环替换带空格的逗号是微不足道的。然后,您可以将结果填充到 Steven 3.2 20
中,并使用std::replace()
使用您已编写的代码将单个空格分隔的值提取到离散变量中。
只是一个小小的警告:如果这确实是你的家庭作业,要编写代码来手动解析和提取逗号分隔的值,就不能保证你的导师会给你完整的成绩。脏兮兮的做法......
答案 1 :(得分:2)
正在施工
Ton,很好的尝试和完整的问题。这是答案:
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所说,但我把它留在这里,以便其他人不会做出同样的尝试! !!!!!!
#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));
{
...
}
没&#39;?吨
因为,在循环之后加一个分号就等于:
while()
{
;
}
因为您可能已经知道只有一行作为正文的循环不需要大括号。
我认为这是循环的主体(即你使用std::stringstream
的部分)发生了什么?
它被执行了! 但只有一次!。
你看,一对大括号本身就意味着什么,它是一个匿名的范围/块。
所以这个:
{
stringstream ss(data);
ss >> arrayData[i].username;
ss >> arrayData[i].gpa;
ss >> arrayData[i].age;
i++;
}
在它的一个上运行,而不是像你想要的那样成为while循环的一部分!
为什么它有用?!因为你在循环之前声明了i
! ;)