从C ++中的.csv文件读取双精度数

时间:2013-11-18 17:16:08

标签: c++ csv vector

您好我在从.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文件或最好看的方法,但我自己想出来,这是可以预料的!提前谢谢!

3 个答案:

答案 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,你需要创建一个临时字符串流,它接受你在外部循环中读取的行,然后在该临时字符串的内部循环中运行getlinefin

答案 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