我正在学习如何使用boost::spirit,即使使用非常简单的解析器,我也面临着一些问题。我正在尝试构建一个解析器,它接受以冒号分隔的数字列表(仅为0或1)。该列表可以有3或4位数。因此,0:0:0
和1:0:1:0
有效,而例如0:0
或0:0:0:0:0
则不是。
在下面的代码中,您可以看到我如何使用可选运算符指定第一个数字可能存在与否。但是,它不起作用(序列0:0:0
的解析失败)。代码有什么问题吗?我会说这是正确的,但我再次开始学习精神。
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;
void parse_tuple(const std::string& tuple) {
using qi::char_;
auto begin = tuple.begin();
auto end = tuple.end();
bool r = qi::parse(begin, end,
-(char_('0', '1') >> ':') >>
char_('0', '1') >> ':' >>
char_('0', '1') >> ':' >>
char_('0', '1')
);
if (!r || begin != end)
throw std::runtime_error("wrong format");
}
int main() {
parse_tuple("0:0:0"); // It fails for this one
parse_tuple("0:0:0:0");
try { parse_tuple("0:0"); } catch (...) {
std::cout << "expected error\n"; }
try { parse_tuple("0:0:0:0:0"); } catch (...) {
std::cout << "expected error\n"; }
}
答案 0 :(得分:1)
下面
bool r = qi::parse(begin, end, -(char_('0', '1') >> ':') >> char_('0', '1') >> ':' >> char_('0', '1') >> ':' >> char_('0', '1') );
可选的char_应该是最后一个而不是第一个。 规则是按顺序应用的,因此当您解析“0:0:0”时,代码的第一行(可选的东西)会通过测试,然后您的规则要求遵循3位数,而不是2位数。
在我看来,您应该使用%运算符来匹配列表,如果您解析了3或4个元素,请稍后再检查。
修改强> 或使用qi::repeat来提高可读性。
答案 1 :(得分:0)
这将是最直接的解决方案:
bool r = qi::parse(begin, end,
char_("01") > ':' >
char_("01") > ':' >
char_("01") > -(':' > char_("01"))
);
完整示例 http://liveworkspace.org/code/3U0QJW$0 :
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
void parse_tuple(const std::string& tuple) {
using qi::char_;
auto begin = tuple.begin();
auto end = tuple.end();
bool r = qi::parse(begin, end,
char_("01") > ':' >
char_("01") > ':' >
char_("01") > -(':' > char_("01"))
);
if (!r || begin != end)
throw std::runtime_error("wrong format");
}
int main() {
parse_tuple("0:0:0"); // It fails for this one
parse_tuple("0:0:0:0");
try { parse_tuple("0:0"); } catch (...) {
std::cout << "expected error\n"; }
try { parse_tuple("0:0:0:0:0"); } catch (...) {
std::cout << "expected error\n"; }
}