Boost Spirit Grammar 检测登录失败

Boost Spirit Grammar To Detect Login Failure

我编写了以下简单语法来检测服务器返回的字符串是否为登录失败。我在 phrase_parse 函数中内联使用它,但由于代码被定期调用,我想创建语法的静态实例。我用的是这个:

bool loginFailed() 
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    // current data is an re2 stringpiece. so .data returns char*
    const char* front = currentData.data();
    const char* back = currentData.end();

    return qi::phrase_parse(front, back, -qi::int_ >> (ascii::no_case[qi::lit("no")] | ascii::no_case[qi::lit("bad")]), qi::space);
}

哪个有效。但是,当我将其翻译成以下内容时,语法似乎总是失败。我想做的是在我的 cpp 文件中:

namespace {
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    struct FailedGrammar : qi::grammar<const char*>
    {
        FailedGrammar() : 
            FailedGrammar::base_type(m_start),
            m_start()
        {
            m_start = -qi::int_ >> (ascii::no_case[qi::lit("no")] | ascii::no_case[qi::lit("bad")]);
        }
        qi::rule<const char*> m_start;
    };

    const FailedGrammar s_failedInstance;
}

然后这样调用:

bool loginFailed() 
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    // current data is an re2 stringpiece. so .data returns char*
    const char* front = currentData.data();
    const char* back = currentData.end();

    return qi::phrase_parse(front, back, s_failedInstance, qi::space);
}

我要识别的字符串是这样的:

0002 NO FAILED LOGIN

其中数字是可选的。我知道使用 re2 执行此操作的其他方法,但是,我正在寻找精神实现。

有没有人有任何指示或失败的潜在原因?

编辑: 我在调试器中发现了很多语法问题。首先,我意识到要解析一个数字,例如我应该写成 *(qi::int_) 的 0002。另外,我去掉了 ascii::space 取而代之的是 ascii::blank

您的第一个版本使用船长。

你的第二个没有¹。您可以修复它:

struct FailedGrammar : qi::grammar<const char*, qi::space_type>
{
    FailedGrammar() : FailedGrammar::base_type(m_start), m_start()
    {
        m_start = -qi::int_ >> (ascii::no_case[qi::lit("no")] | ascii::no_case[qi::lit("bad")]);
    }
    qi::rule<const char*, qi::space_type> m_start;
};

注意:使用qi::space/qi::lit和ascii::no_case是不一致的。你可以大大简化。

Live On Coliru

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

namespace login_detection {
    using namespace boost::spirit::qi;
    static const rule<const char*> s_failed = skip(space) [ no_case [ -int_ >> lit("no") | "bad" ] ];
}

bool loginFailed2(boost::string_ref response) {
    return parse(response.begin(), response.end(), login_detection::s_failed);
}

int main() {
    return loginFailed2("0002 NO FAILED LOGIN")? 1 : 2;
}

事实上,很少或根本没有理由在命名空间范围内制定规则:

bool loginFailed2(boost::string_ref response) {
    using namespace boost::spirit::qi;
    static const rule<const char*> s_failed = skip(space) [ no_case [ -int_ >> lit("no") | "bad" ] ];
    return parse(response.begin(), response.end(), s_failed);
}

不过,我建议比较生成的程序集,因为我认为我会 相同

bool loginFailed2(boost::string_ref response) {
    using namespace boost::spirit::qi;
    return phrase_parse(response.begin(), response.end(), no_case [ -int_ >> lit("no") | "bad" ], space);
}

¹ Boost spirit skipper issues