使用Boost.Spirit仅解析特定数字

时间:2016-05-19 10:22:58

标签: c++ boost boost-spirit

如何构建仅匹配特定范围内的数字的Boost.Spirit解析器?

考虑简单的解析器qi::uint_。它匹配所有无符号整数。是否可以构建一个匹配数字012345但不是12346和更大的解析器?

1 个答案:

答案 0 :(得分:6)

一种方法是将qi::uint_解析器附加一个语义操作,该操作检查解析器的属性并相应地设置语义操作的第三个参数:

#include <iostream>
#include <string>
#include <vector>

#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;

int main() {
  qi::rule<std::string::const_iterator, unsigned(), qi::ascii::space_type> rule;

  const auto not_greater_than_12345 = [](const unsigned& attr, auto&, bool& pass) {
    pass = !(attr > 12345U);
  };
  rule %= qi::uint_[not_greater_than_12345];

  std::vector<std::string> numbers{"0", "123", "1234", "12345", "12346", "123456"};
  for (const auto& number : numbers) {
    unsigned result;
    auto iter = number.cbegin();
    if (qi::phrase_parse(iter, number.cend(), rule, qi::ascii::space, result) &&
        iter == number.cend()) {
      std::cout << result << '\n';  // 0 123 1234 12345
    }
  }
}

Live on Wandbox

可以使用the Phoenix placeholders _pass and _1更简洁地编写语义操作:

#include <iostream>
#include <string>
#include <vector>

#include <boost/phoenix/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;

int main() {
  qi::rule<std::string::const_iterator, unsigned(), qi::ascii::space_type> rule;

  rule %= qi::uint_[qi::_pass = !(qi::_1 > 12345U)];

  std::vector<std::string> numbers{"0", "123", "1234", "12345", "12346", "123456"};
  for (const auto& number : numbers) {
    unsigned result;
    auto iter = number.cbegin();
    if (qi::phrase_parse(iter, number.cend(), rule, qi::ascii::space, result) &&
        iter == number.cend()) {
      std::cout << result << '\n';  // 0 123 1234 12345
    }
  }
}

Live on Wandbox

来自Semantic Actions with Parsers

  

用作语义动作的函数的可能签名是:

...
template <typename Attrib, typename Context>
void fa(Attrib& attr, Context& context, bool& pass);
     

...这里Attrib是附加到语义动作的解析器的属性类型。 ...语义操作可以使用第三个参数pass来强制关联的解析器失败。如果pass设置为false,则操作解析器也将立即返回false,而不调用p并且不生成任何输出。