Question

Using boost spirit, I'd like to extract a string that is followed by some data in parentheses. The relevant string is separated by a space from the opening parenthesis. Unfortunately, the string itself may contain spaces. I'm looking for a concise solution that returns the string without a trailing space.

The following code illustrates the problem:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <string>
#include <iostream>

namespace qi = boost::spirit::qi;
using std::string;
using std::cout;
using std::endl;

void
test_input(const string &input)
{
    string::const_iterator b = input.begin();
    string::const_iterator e = input.end();
    string parsed;
    bool const r = qi::parse(b, e,
        *(qi::char_ - qi::char_("(")) >> qi::lit("(Spirit)"),
            parsed
    );
    if(r) {
        cout << "PASSED:" << endl;
    } else {
        cout << "FAILED:" << endl;
    }
    cout << "  Parsed: \"" << parsed << "\"" << endl;
    cout << "  Rest: \"" << string(b, e) << "\"" << endl;
}

int main()
{
    test_input("Fine (Spirit)");
    test_input("Hello, World (Spirit)");

    return 0;
}

Its output is:

PASSED:
  Parsed: "Fine "
  Rest: ""
PASSED:
  Parsed: "Hello, World "
  Rest: ""

With this simple grammar, the extracted string is always followed by a space (that I 'd like to eliminate).

The solution should work within Spirit since this is only part of a larger grammar. (Thus, it would probably be clumsy to trim the extracted strings after parsing.)

Thank you in advance.

Was it helpful?

Solution

Like the comment said, in the case of a single space, you can just hard code it. If you need to be more flexible or tolerant:

I'd use a skipper with raw to "cheat" the skipper for your purposes:

bool const r = qi::phrase_parse(b, e,
    qi::raw [ *(qi::char_ - qi::char_("(")) ] >> qi::lit("(Spirit)"),
    qi::space,
    parsed
);

This works, and prints

PASSED:
  Parsed: "Fine"
  Rest: ""
PASSED:
  Parsed: "Hello, World"
  Rest: ""

See it Live on Coliru

Full program for reference:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <string>
#include <iostream>

namespace qi = boost::spirit::qi;
using std::string;
using std::cout;
using std::endl;

void
test_input(const string &input)
{
    string::const_iterator b = input.begin();
    string::const_iterator e = input.end();
    string parsed;
    bool const r = qi::phrase_parse(b, e,
        qi::raw [ *(qi::char_ - qi::char_("(")) ] >> qi::lit("(Spirit)"),
        qi::space,
        parsed
    );
    if(r) {
        cout << "PASSED:" << endl;
    } else {
        cout << "FAILED:" << endl;
    }
    cout << "  Parsed: \"" << parsed << "\"" << endl;
    cout << "  Rest: \"" << string(b, e) << "\"" << endl;
}

int main()
{
    test_input("Fine (Spirit)");
    test_input("Hello, World (Spirit)");

    return 0;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top