Search code examples
c++parsingifstream

How to parse line-by-line using ifstream


If I wanted to parse from a file line-by-line and store the data in separate variables, using getline to store into a string and parse/convert to separate variables seems like a long way to do it. For example, for line "ABC a1 1 2 3", if I wanted to store the first two data into strings and the rest of the three into integers, what would be an efficient way to read from the file line-by-line and store it accordingly?


Solution

  • Boost.Spirit is suited for parsing custom data formats with your own grammar.

    #include <iostream>
    #include <sstream>
    #include <string>
    #include <tuple>
    
    #include <boost/fusion/include/std_tuple.hpp>
    #include <boost/spirit/home/x3.hpp>
    
    std::tuple<std::string, std::string, int, int, int>
    parse(std::string const &input)
    {
        auto iter = input.begin();
    
        using namespace boost::spirit::x3;
    
        auto name = rule<class name, std::string>{}
            = lexeme[upper >> *upper];
        auto ident = rule<class ident, std::string>{}
            = lexeme[alpha >> *alnum];
    
        std::tuple<std::string, std::string, int, int, int> result;
    
        bool r = phrase_parse(iter, input.end(),
                              name > ident > int_ > int_ > int_,
                              space, result);
    
        if (!r || iter != input.end())
        {
            std::string rest(iter, input.end());
            throw std::invalid_argument("Parsing failed at " + rest);
        }
    
        return result;
    }
    
    
    int main()
    {
        // This could be a file instead with std::ifstream
        std::istringstream input;
        input.str("ABC a1 1 2 3\nDEF b2 4 5 6\n");
    
        for (std::string line; std::getline(input, line); )
        {
            std::string name, ident;
            int a, b, c;
            std::tie(name,ident,a,b,c) = parse(line);
    
            std::cout << "Found the following entries:\n"
                      << "Name: " << name << "\n"
                      << "Identifier: " << ident << "\n"
                      << "a: " << a << "\n"
                      << "b: " << b << "\n"
                      << "c: " << c << "\n";
        }
    }
    

    Live example