I have the following string
GOOSE BAY LATITUDE 53.27 LONGITUDE 299.60 ALTITUDE 46 M
that I need to parse into the variables using Boost spirit.
Currently I have a code as follows:
qi::rule < string::const_iterator, std::string(), asc::space_type> any_string;
any_string %= as_string [lexeme[+(asc::char_ - asc::space)]];
r = phrase_parse(first, last,
(any_string[ph::ref(station) = _1] >> "LATITUDE" >>
double_[ph::ref(lat) = _1] >> "LONGITUDE" >> double_[ph::ref(lon) = _1] >>
"ALTITUDE" >> double_[ph::ref(alt) = _1] >> "M"), asc::space);
that works fine (that is, stores station, lat, lon, alt variables) IF before "LATITUDE" I have just one word.
However I need also to store into variable station anything before "LATITUDE", should it be one or few (not just two, as in example) words. BUT it must NOT consume anyting following "LATITUDE" word, so latitude etc. still go to their own variables. Please help me with figuring out the proper Boost Spirit expression to recognise into station everything that is seen in the line, spaces included, up to special word (LATITUDE in the example above).
Notes:
asc::graph
is equivalent to asc::char_ - asc::space
.lexeme
is redundant if you declare the rule without a skipper (see also Boost spirit skipper issues)
qi::rule<It> any_string = +qi::graph_;
just assert negative match for the first keyword at each character in the first field:
+(qi::char_ - "LATITUDE")
you can pass references to the phrase_parse
API so you can do without the semantic action (see also Boost Spirit: "Semantic actions are evil"?):
bool r = qi::phrase_parse(first, last,
( qi::raw [ +(qi::char_ - "LATITUDE") ] >> "LATITUDE" >>
qi::double_ >> "LONGITUDE" >>
qi::double_ >> "ALTITUDE" >>
qi::double_ >> "M"),
asc::space,
name, lat, lon, alt);
See it Live On Coliru
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
namespace asc= boost::spirit::ascii;
int main()
{
typedef std::string::const_iterator It;
std::string const input("GOOSE BAY LATITUDE 53.27 LONGITUDE 299.60 ALTITUDE 46 M");
std::string name;
double lat, lon, alt;
It first(input.begin()), last(input.end());
bool r = qi::phrase_parse(first, last,
(qi::raw [ +(qi::char_ - "LATITUDE") ] >> "LATITUDE" >>
qi::double_ >> "LONGITUDE" >>
qi::double_ >> "ALTITUDE" >>
qi::double_ >> "M"),
asc::space,
name, lat, lon, alt);
if (r)
std::cout << "Parsed: '" << name << "' lat:" << lat << " lon:" << lon << " alt:" << alt << "\n";
else
std::cout << "Failed\n";
if (first != last)
std::cout << "Remaining input: '" << std::string(first, last) << "'\n";
}