我仍然是Boost精神的新手。
我正在尝试解析一个带有可能的lead和尾随空格和中间空格的字符串。我想用字符串
执行以下操作例如
"( my test1 ) (my test2)"
被解析为两个术语 -
"my test1"
"my test2"
我使用了以下逻辑
using boost::spirit::qi;
struct Parser : grammar<Iterator, attribType(), space_type>
{
public:
Parser() : Parser::base_type(term)
{
group %= '(' >> (group | names) >> ')';
names %= no_skip[alnum][_val=_1];
}
private:
typedef boost::spirit::qi::rule<Iterator, attribType(), space_type> Rule;
Rule group;
Rule names
}
虽然它允许保留其间的空间。不幸的是,它还保持标题和尾随空格和多个中间空格。我想找到一个更好的逻辑。
我确实看到了使用自定义队列头文件与boost :: spirit :: qi :: skip online的引用,但我没有遇到过有用的空格示例。有没有其他人有经验呢?
答案 0 :(得分:2)
我建议在之后(而不是在解析期间)进行修剪/规范化。
那就是说,你可以像这样破解它:
name %= lexeme [ +alnum ];
names %= +(name >> (&lit(')') | attr(' ')));
group %= '(' >> (group | names) >> ')';
输出:
Parse success
Term: 'my test1'
Term: 'my test2'
为了便于阅读,我引入了name
规则。请注意,(&lit(')') | attr(' '))
是一种奇特的说法:
如果下一个字符匹配
')'
则不执行任何操作,否则,将' '
附加到合成属性
完整代码:
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
using Iterator = std::string::const_iterator;
using attribType = std::string;
struct Parser : qi::grammar<Iterator, attribType(), qi::space_type>
{
public:
Parser() : Parser::base_type(group)
{
using namespace qi;
name %= lexeme [ +alnum ];
names %= +(name >> (&lit(')') | eps [ phx::push_back(_val, ' ') ]));
group %= '(' >> (group | names) >> ')';
BOOST_SPIRIT_DEBUG_NODES((name)(names)(group))
}
private:
typedef boost::spirit::qi::rule<Iterator, attribType(), qi::space_type> Rule;
Rule group, names, name;
};
int main()
{
std::string const input = "( my test1 ) (my test2)";
auto f(input.begin()), l(input.end());
Parser p;
std::vector<attribType> data;
bool ok = qi::phrase_parse(f, l, *p, qi::space, data);
if (ok)
{
std::cout << "Parse success\n";
for(auto const& term : data)
std::cout << "Term: '" << term << "'\n";
}
else
{
std::cout << "Parse failed\n";
}
if (f!=l)
std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'\n";
}