您好我在从.csv文件中正确读取值时遇到了一些麻烦。我想用1000个用户定义的对象(DetectedParticle)填充一个向量,并从文件中分配变量。该对象具有double类型的4个成员变量(x0,x1,x2,x3)。在文件中,每一行应该对应于向量中的单个条目,并且该行的每一列都需要被读入对象中的相应变量。
文件格式如下(不包括评论):
wordswordswordswordswords
2.231,23.52,123.4,213.2 //first object to be created with these values
23213,23123,41234,45236 //second
21323,123123,123123,2435 //third
.
.
.
23434,234234,234234,234 //1000th
问题是它只能在向量中读取每一行。因此,向量将在单词之后的第一行中有一个对象,然后它将具有第三行,但它将错过第二行。因此,我有一个大小为499而不是大小为1000的向量。它成功地将列分配给正确的成员变量,但它只是没有做足够多次!这是代码片段:
std::vector<DetectedParticle> populate(std::string file){ //DetectedParticle is my user defined type with membervariables x0,x1,x2,x3
std::vector<DetectedParticle> temp; //creates a vector of Detected Particles for later returning
std::ifstream fin("detectedpositrons.csv"); //ifstream to read from
std::string linestr; //string for the stream to be read into
if (!fin.is_open()) { std::cerr << "failed to open file\n"; } // check file is open, error message if not
fin.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' ); //ignores first
while ( std::getline(fin, linestr) ){ //
int i = 0;
DetectedParticle temppart;
while ( std::getline(fin,linestr,',') )
{
if (i == 4){temp.push_back(temppart); break;} //when it gets to teh end of the line, past the 4th column, it breaks and should go to the next line
float holder ; //float for the string to be held in
std::istringstream(linestr) >> holder; //converts string to float
if(i == 0){ temppart.x0 = holder; i++;} //if first column, sets x0 equal to the value
else if (i == 1){ temppart.x1 = holder; i++;} //if second column, sets x1 = to value
else if (i == 2){ temppart.x2 = holder; i++;} //if 3rd column sets x2= value
else if (i == 3){ temppart.x3 = holder; i++;} //if last column it populates the last value x3 with that value.
}
}
return temp; //returns the populated vector
}
很抱歉,如果不容易理解或以最直观的方式阅读csv文件或最好看的方法,但我自己想出来,这是可以预料的!提前谢谢!
答案 0 :(得分:1)
问题是你读了一行,什么都不做,然后读下一行解析:
while ( std::getline(fin, linestr) ) // first read
{
...
while ( std::getline(fin,linestr,',') ) // second read
{
// you are doing stuff here
}
}
我认为您只想丢弃标题行(根据您的描述),因此您应该在循环之外进行一次std::getline
调用,然后循环std::getline
调用以进行读取双重值:
std::getline(fin, linestr); // header row - throw away
while (std::getline(fin, linestr))
{
istringstream iss(linestr);
// parse the stringstream into your vectors - I wouldn't use getline here, but you could
}
答案 1 :(得分:0)
你丢弃了外圈(while ( std::getline(fin, linestr) ){
)中的线条。你滥用getline将输入切换成组成部分 - 这是膨胀的,但你没有使用你已经读过的行。
如果你坚持这个hack,你需要创建一个临时字符串流,它接受你在外部循环中读取的行,然后在该临时字符串的内部循环中运行getline
在fin
上,不。
答案 2 :(得分:0)
使用Boost Spirit。
这是一个你可以适应的例子。它会解析输入行,查找4个以逗号分隔的双精度值,并填充std::vector
std::tuple<double, double, double, double>
:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/home/phoenix/object/construct.hpp>
#include <boost/spirit/home/phoenix/container.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <iostream>
#include <string>
#include <tuple>
typedef std::tuple<double, double, double, double> particle;
typedef std::vector<particle> Particles;
template <typename Iterator>
bool populate_vector(Iterator first, Iterator last, Particles& vector)
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
bool r = qi::phrase_parse(first, last,
(
(qi::double_ >> ',' >> qi::double_>> ',' >> qi::double_ >> ',' >> qi::double_)
[
phoenix::push_back(phoenix::ref(vector),
phoenix::construct<particle>(qi::_1, qi::_2 , qi::_3, qi::_4))
]
), qi::space);
return r;
}
int main()
{
std::string str;
Particles particles;
while (getline(std::cin, str))
{
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
{
break;
}
if (populate_vector(str.begin(), str.end(), particles))
{
std::cout << "Parsing succeeded: " << particles.size() << std::endl;
}
else
{
std::cout << "Parsing failed." << std::endl;
}
}
return 0;
}
互动示例:
1.26,1.23,1.6,152
Parsing succeeded: 1
1,2,3,4
Parsing succeeded: 2