提升精神解析字符串,包含前导和尾随空格

时间:2014-07-21 14:27:07

标签: c++ boost whitespace boost-spirit boost-spirit-qi

我仍然是Boost精神的新手。

我正在尝试解析一个带有可能的lead和尾随空格和中间空格的字符串。我想用字符串

执行以下操作
  1. 删除所有尾随和前导空格
  2. 将中间字空间限制为一个空格
  3. 例如

    "(  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的引用,但我没有遇到过有用的空格示例。有没有其他人有经验呢?

1 个答案:

答案 0 :(得分:2)

我建议在之后(而不是在解析期间)进行修剪/规范化

那就是说,你可以像这样破解它:

name   %= lexeme [ +alnum ];
names  %= +(name >> (&lit(')') | attr(' ')));
group  %= '(' >> (group | names) >> ')';

查看 Live On Coliru

输出:

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";
}