I've a string like the following one:
[GENERAL]
FMax Antenna = 3000
FMin Antenna = 2000
Invalid key = Invalid value
EMin Antenna = -50
EMax Antenna = 80
I want to parse it in order to save the value of FMin Antenna
, FMax Antenna
, EMin Antenna
, EMax Antenna
in a structure. I've created a Spirit parser, but it works partially.
Since the file can have many key = value
rows, I need to parse only what I need (the key values that I must read) ignoring other pairs.
Both key
and value
can be alphanumeric strings with spaces and tabs.
I've defined inside the parser the keys that I want to read but when I encounter an unknown key, I cannot read keys that follows it (in the example case, I can't read EMin Antenna
and EMax Antenna
because are defined after an unknown key).
I've tried the code below: If I parse file1
, that contains only keys that I want to read, it works, but if I add unknown key = value
pairs in the middle of the file, like in file2
, it stops to read all subsequent lines.
How can I fix it and continue to parse the file after unknown key-value pairs?
#include <boost/optional/optional_io.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
const std::string file1 = R"xx(
[GENERAL]
FMax Antenna = 3000
FMin Antenna = 2000
EMin Antenna = -50
EMax Antenna = 80
)xx";
const std::string file2 = R"xx(
[GENERAL]
FMax Antenna = 3000
FMin Antenna = 2000
EMin Antenna = -50
pappa pio = po po
EMax Antenna = 80
Ciao = 55
)xx";
struct Data {
double minFrequency = 0.0;
double maxFrequency = 0.0;
double minElevation = 0.0;
double maxElevation = 0.0;
};
BOOST_FUSION_ADAPT_STRUCT(
Data,
(double, minFrequency)
(double, maxFrequency)
(double, minElevation)
(double, maxElevation)
)
template <typename It, typename Skipper = qi::space_type>
struct grammar : qi::grammar<It, Data(), Skipper> {
grammar() : grammar::base_type(start) {
auto minFrequency = bind(&Data::minFrequency, qi::_val);
auto maxFrequency = bind(&Data::maxFrequency, qi::_val);
auto minElevation = bind(&Data::minElevation, qi::_val);
auto maxElevation = bind(&Data::maxElevation, qi::_val);
start = qi::no_case["[GENERAL]"] >> *(
("FMin Antenna" >> qi::lit('=') >> qi::int_)[minFrequency = qi::_1] |
("FMax Antenna" >> qi::lit('=') >> qi::int_)[maxFrequency = qi::_1] |
("EMin Antenna" >> qi::lit('=') >> qi::int_)[minElevation = qi::_1] |
("EMax Antenna" >> qi::lit('=') >> qi::int_)[maxElevation = qi::_1] |
(+(qi::alnum | qi::blank) >> qi::lit('=') >> +(qi::alnum | qi::blank)) // Issue here?
);
}
private:
qi::rule<It, Data(), Skipper> start;
};
int main() {
using It = std::string::const_iterator;
Data parsed1, parsed2;
bool ok = qi::phrase_parse(file1.begin(), file1.end(), grammar<It>(), qi::space, parsed1);
std::cout << "--- File 1 ---" << std::endl;
std::cout << "parsed = " << std::boolalpha << ok << std::endl;
std::cout << "min freq = " << parsed1.minFrequency << std::endl;
std::cout << "max freq = " << parsed1.maxFrequency << std::endl;
std::cout << "min elev = " << parsed1.minElevation << std::endl;
std::cout << "max elev = " << parsed1.maxElevation << std::endl;
std::cout << "--- File 2 ---" << std::endl;
ok = qi::phrase_parse(file2.begin(), file2.end(), grammar<It>(), qi::space, parsed2);
std::cout << "parsed = " << std::boolalpha << ok << std::endl;
std::cout << "min freq = " << parsed2.minFrequency << std::endl;
std::cout << "max freq = " << parsed2.maxFrequency << std::endl;
std::cout << "min elev = " << parsed2.minElevation << std::endl;
std::cout << "max elev = " << parsed2.maxElevation << std::endl;
return 0;
}
Ouput:
--- File 1 ---
parsed = true
min freq = 2000
max freq = 3000
min elev = -50
max elev = 80
--- File 2 ---
parsed = true
min freq = 2000
max freq = 3000
min elev = -50
max elev = 0 <-- This should be 80 like in the first parsing