C++ string parsing (python style)

后端 未结 10 1131
伪装坚强ぢ
伪装坚强ぢ 2020-12-08 07:52

I love how in python I can do something like:

points = []
for line in open(\"data.txt\"):
    a,b,c = map(float, line.split(\',\'))
    points += [(a,b,c)]
<         


        
相关标签:
10条回答
  • 2020-12-08 08:24

    I`d do something like this:

    ifstream f("data.txt");
    string str;
    while (getline(f, str)) {
        Point p;
        sscanf(str.c_str(), "%f, %f, %f\n", &p.x, &p.y, &p.z); 
        points.push_back(p);
    }
    

    x,y,z must be floats.

    And include:

    #include <iostream>
    #include <fstream>
    
    0 讨论(0)
  • 2020-12-08 08:24

    Fun with Boost.Tuples:

    #include <boost/tuple/tuple_io.hpp>
    #include <vector>
    #include <fstream>
    #include <iostream>
    #include <algorithm>
    
    int main() {
        using namespace boost::tuples;
        typedef boost::tuple<float,float,float> PointT;
    
        std::ifstream f("input.txt");
        f >> set_open(' ') >> set_close(' ') >> set_delimiter(',');
    
        std::vector<PointT> v;
    
        std::copy(std::istream_iterator<PointT>(f), std::istream_iterator<PointT>(),
                 std::back_inserter(v)
        );
    
        std::copy(v.begin(), v.end(), 
                  std::ostream_iterator<PointT>(std::cout)
        );
        return 0;
    }
    

    Note that this is not strictly equivalent to the Python code in your question because the tuples don't have to be on separate lines. For example, this:

    1,2,3 4,5,6
    

    will give the same output than:

    1,2,3
    4,5,6
    

    It's up to you to decide if that's a bug or a feature :)

    0 讨论(0)
  • 2020-12-08 08:24

    You could read the file from a std::iostream line by line, put each line into a std::string and then use boost::tokenizer to split it. It won't be quite as elegant/short as the python one but a lot easier than reading things in a character at a time...

    0 讨论(0)
  • 2020-12-08 08:30

    This answer is based on the previous answer by j_random_hacker and makes use of Boost Spirit.

    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <string>
    #include <boost/spirit.hpp>
    
    using namespace std;
    using namespace boost;
    using namespace boost::spirit;
    
    struct Point {
        double a, b, c;
    };
    
    int main(int argc, char **argv) 
    {
        vector<Point> points;
    
        ifstream f("data.txt");
    
        string str;
        Point p;
        rule<> point_p = 
               double_p[assign_a(p.a)] >> ',' 
            >> double_p[assign_a(p.b)] >> ',' 
            >> double_p[assign_a(p.c)] ; 
    
        while (getline(f, str)) 
        {
            parse( str, point_p, space_p );
            points.push_back(p);
        }
    
        // Do something with points...
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-08 08:34

    The C++ String Toolkit Library (StrTk) has the following solution to your problem:

    #include <string>
    #include <deque>
    #include "strtk.hpp"
    
    struct point { double x,y,z; }
    
    int main()
    {
       std::deque<point> points;
       point p;
       strtk::for_each_line("data.txt",
                            [&points,&p](const std::string& str)
                            {
                               strtk::parse(str,",",p.x,p.y,p.z);
                               points.push_back(p);
                            });
       return 0;
    }
    

    More examples can be found Here

    0 讨论(0)
  • 2020-12-08 08:37

    All these good examples aside, in C++ you would normally override the operator >> for your point type to achieve something like this:

    point p;
    while (file >> p)
        points.push_back(p);
    

    or even:

    copy(
        istream_iterator<point>(file),
        istream_iterator<point>(),
        back_inserter(points)
    );
    

    The relevant implementation of the operator could look very much like the code by j_random_hacker.

    0 讨论(0)
提交回复
热议问题