简体   繁体   English

从C ++中的.csv文件读取双打

[英]reading doubles from a .csv file in C++

Hello I'm having a bit of trouble getting my values to read properly from a .csv file. 您好,让我无法从.csv文件正确读取值时遇到麻烦。 I want to populate a vector with 1000 user defined objects (DetectedParticle), with their variables assigned from the file. 我想用1000个用户定义的对象(DetectedParticle)填充矢量,并从文件中分配它们的变量。 The object has 4 member variables (x0,x1,x2,x3) of type double. 该对象具有4个类型为double的成员变量(x0,x1,x2,x3)。 In the file each line ought to correspond to a single entry in the vector, and each column of the line needs to be read into its respective variable in the object. 在文件中,每一行应对应于向量中的单个条目,并且该行的每一列都需要读入对象中的相应变量。

The file format is like this (excluding the comments): 文件格式如下(不包括注释):

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

The problem is it only reads in every other line into the vector. 问题在于它仅每隔一行读入向量。 So the vector will have an object in from the first line after the words, and then it'll have the third line but it'll miss out the second line. 因此,向量将在单词后的第一行中有一个对象,然后它将具有第三行,但会漏掉第二行。 As a result I have a vector of size 499 rather than size 1000. It is successfully assigning the column to the correct member variable though, it's just not doing it enough times! 结果,我得到的矢量大小为499,而不是大小1000。尽管它已成功地将列分配给了正确的成员变量,但这样做的次数还不够! Here's the code snippet: 这是代码片段:

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
}

Sorry if it's not easy to follow or the most intuitive way to read a csv file or the nicest looking method but I came up with it myself so that's to be expected! 很抱歉,如果它不是很容易遵循,也不是最直观的方式读取csv文件或最漂亮的方法,但是我自己想出了它,这是可以预期的! Thanks in advance! 提前致谢!

The problem is you read a line, do nothing with it, and then read the next line to parse: 问题是您读了一行,不执行任何操作,然后阅读下一行进行解析:

while ( std::getline(fin, linestr) ) // first read
{
    ...
    while ( std::getline(fin,linestr,',') ) // second read
    {
        // you are doing stuff here
    }
}

I think you want to just discard the header row (based on your description), so you should have a single std::getline call outside of a loop, and then a looped std::getline call to read in the double values: 我认为您只是想丢弃标题行(根据您的描述),因此您应该在循环外部进行一个std::getline调用,然后再执行一个循环的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
}

You're discarding the line you've got in your outer loop ( while ( std::getline(fin, linestr) ){ ). 您将丢弃外部循环中的行( while ( std::getline(fin, linestr) ){ )。 You're abusing getline to chop input into constituent parts - that's be swell, but you're not using the line you've already read. 您正在滥用getline来将输入砍成组成部分-这真是棒极了,但是您没有使用已经读过的行。

If you insist on this hack, you need to create a temporary string stream that takes the line you've read in the outer loop, and then run getline in the inner loop on that temporary string stream , not on fin . 如果您坚持要进行这种破解,则需要创建一个临时字符串流,该字符串流将在外部循环中读取已读取的行,然后在该临时字符串流而非 fin的内部循环中运行getline

Use Boost Spirit . 使用Boost Spirit

Here is an example you can adapt. 这是您可以适应的示例。 It does parse the input line looking for 4 comma separated double values and populate a std::vector of std::tuple<double, double, double, double> : 它确实解析输入行以查找4个逗号分隔的double值,并填充std::tuple<double, double, double, double>std::vector

#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;
}

Interaction example: 互动示例:

1.26,1.23,1.6,152
Parsing succeeded: 1
1,2,3,4
Parsing succeeded: 2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM