如何构建仅匹配特定范围内的数字的Boost.Spirit解析器?
考虑简单的解析器qi::uint_
。它匹配所有无符号整数。是否可以构建一个匹配数字0
到12345
但不是12346
和更大的解析器?
答案 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
}
}
}
可以使用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
}
}
}
来自Semantic Actions with Parsers
用作语义动作的函数的可能签名是:
... template <typename Attrib, typename Context> void fa(Attrib& attr, Context& context, bool& pass);
...这里
Attrib
是附加到语义动作的解析器的属性类型。 ...语义操作可以使用第三个参数pass
来强制关联的解析器失败。如果pass
设置为false,则操作解析器也将立即返回false,而不调用p并且不生成任何输出。