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?
Asked
Active
Viewed 586 times
0
-
1C++ does not have a reputation of having a bunch of shortcuts, that make things fast and easy. Using `std::getline()`, then parsing each line, is the most hassle-free, and simplest approach. stackoverflow.com is littered with endless,flaming wreckage that results from attempting to use the formatted extraction `>>` operator to deal with line-oriented input. Don't do it. `std::getline()` is your friend. Learn it. Love it. – Sam Varshavchik Dec 04 '17 at 02:55
-
Honestly in my mind I think you should be storing in a `vector
` then use this to parse the individual `string`s: https://stackoverflow.com/q/32991193/2642059 but because of the vagueness of the question I can't guarantee this is the right answer. – Jonathan Mee Dec 04 '17 at 03:55 -
if every line have same representation, `while(cin >> s1 >> s2 >> i1 >> i2 >> i3) save values;` is a way. – apple apple Dec 04 '17 at 04:00
-
The above method worked the best. Thanks – Joe Dec 11 '17 at 19:13
1 Answers
0
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";
}
}

Henri Menke
- 10,705
- 1
- 24
- 42