Simple C++ input from file…how to?

后端 未结 4 1284
执笔经年
执笔经年 2021-02-03 16:35

I have a file:

P 0.5 0.6 0.3
30 300
80 150
160 400
200 150
250 300
T
r  45 0 0
s 0.5 1.5 0 0
t 200 –150
.
.
.

When I read in \'P\' I know that

4条回答
  •  慢半拍i
    慢半拍i (楼主)
    2021-02-03 17:17

    I'll show you what I think it's the proper C++ way of doing this. First define a class for representing your first line and for doing its IO:

    struct FirstLine
    {
        double x, y, z;
        friend std::istream & operator>>(std::istream & is, FirstLine & data)
        {
            std::string line, ignore;
            std::getline(is, line);
            std::istringstream iss(line);
            iss >> ignore >> data.x >> data.y >> data.z;
            assert(ignore == "P" && iss);
            return is;
        }
        friend std::ostream & operator<<(std::ostream & os, FirstLine const & data)
        {
            return os << "P " << data.x << " " << data.y << " " << data.z;
        }    
    };
    

    I've added some basic error checking with assert, you'll probably want something more robust in your final program.

    Now a class for middle lines:

    struct MiddleLine
    {
        double x, y;
        friend std::istream & operator>>(std::istream & is, MiddleLine & data)
        {
            std::string line;
            std::getline(is, line);
            if(line == "T")
                is.clear(std::ios::failbit);
            else
            {
                int n = sscanf(line.c_str(), "%lf %lf", &data.x, &data.y);
                assert(n == 2);
            }
            return is;
        }
        friend std::ostream & operator<<(std::ostream & os, MiddleLine const & data)
        {
            return os << data.x << " " << data.y;
        }    
    };
    

    When we reach the end of the section where the middle lines are we are supposed to encounter a "T". In that case we raise the fail bit of the stream, which will tell client that there are no more middle lines to read.

    Finally a class for the last lines:

    struct LastLine
    {
        std::string identifier; // r, s or t
        std::vector values;
        friend std::istream & operator>>(std::istream & is, LastLine & data)
        {
            std::string line;
            std::getline(is, line);
            std::istringstream iss(line);
            iss >> data.identifier;
            assert(data.identifier == "r" || data.identifier == "s" 
                   || data.identifier == "t");
            std::copy(std::istream_iterator(iss), 
                      std::istream_iterator(), std::back_inserter(data.values));
            return is;
        }
        friend std::ostream & operator<<(std::ostream & os, LastLine const & data)
        {
            os << data.identifier << " ";
            std::copy(data.values.begin(), data.values.end(),
                      std::ostream_iterator(os, " "));
            return os;
        }      
    };
    

    Last lines are more complicated becase we don't know how many values are in each, so we just read as many as we can.

    That was the tricky part. Now our main function will simply read one first line, then an unknown number of middle lines, and finally an unknown number of last lines:

    int main()
    {
        std::string const data = "P 0.5 0.6 0.3\n
                                 "30 300\n"
                                 "80 150\n"
                                 "160 400\n"
                                 "200 150\n"
                                 "250 300\n"
                                 "T\n"
                                 "r  45 0 0\n"
                                 "s 0.5 1.5 0 0\n"
                                 "t 200 –150";
    
        std::istringstream iss(data);
    
        FirstLine first_line;
        iss >> first_line;
    
        std::vector middle_lines;
        std::copy(std::istream_iterator(iss), 
                  std::istream_iterator(), 
                  std::back_inserter(middle_lines));
        iss.clear();
    
        std::vector last_lines;
        std::copy(std::istream_iterator(iss), 
                  std::istream_iterator(), 
                  std::back_inserter(last_lines));
        assert(iss.eof());       
    
        std::cout << first_line << "\n";
        std::copy(middle_lines.begin(), middle_lines.end(),
                  std::ostream_iterator(std::cout, "\n"));
        std::copy(last_lines.begin(), last_lines.end(),
                  std::ostream_iterator(std::cout, "\n"));
        return 0;
    }
    

    This is the output you'll get::

    P 0.5 0.6 0.3
    30 300
    80 150
    160 400
    200 150
    250 300
    r 45 0 0
    s 45 0 0 0.5 1.5 0 0
    t 45 0 0 0.5 1.5 0 0 200
    

    I've used a string as the source of my data but you'll probably want to read from a file.

    And that's all, you can see that I didn't write a single loop.

    Here's the code in codepad.

提交回复
热议问题