1

我正在学习如何使用boost::spirit,即使使用非常简单的解析器,我也面临一些问题。我正在尝试构建一个解析器,它接受由冒号分隔的数字列表(只有 0 或 1)。该列表可以有 3 位或 4 位数字。因此,0:0:0并且1:0:1:0是有效的,而例如0:00:0:0:0:0不是。

在下面的代码中,您可以看到我如何使用可选运算符来指定第一个数字可能存在或不存在。但是,它不起作用(对 sequence 的解析失败0:0:0)。代码有什么问题吗?我会说这是正确的,但我还是刚刚开始学习 Spirit。

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

2 回答 2

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来提高可读性。

于 2012-12-14T22:50:09.143 回答
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"; }
}
于 2012-12-15T01:31:34.150 回答