Boost Spirit 语法检测登录失败

Posted

技术标签:

【中文标题】Boost Spirit 语法检测登录失败【英文标题】:Boost Spirit Grammar To Detect Login Failure 【发布时间】:2016-11-11 19:02:02 【问题描述】:

我编写了以下简单的语法来检测服务器返回的字符串是否为登录失败。我在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 执行此操作的其他方法,但是,我正在寻找一种精神实现。

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

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

【问题讨论】:

"我意识到要解析一个数字,例如 0002 我应该写 *(qi::int_)" - 如果数字不是可选的,请使用 qi::uint_+qi::digit 甚至 @ 987654331@ 对空白的好想法。我几乎要提到它,但我对你的“语法”一无所知,不想复杂化 【参考方案1】:

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

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

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

【讨论】:

非常详细的答案!谢谢!

以上是关于Boost Spirit 语法检测登录失败的主要内容,如果未能解决你的问题,请参考以下文章

防止 Boost Spirit Symbol 解析器过早接受关键字

Boost.Spirit 的单元测试

Boost.Spirit.X3 中的船长

Boost Spirit编译问题

无法使用 Boost Spirit X3 解析空的 C++ 结构

sql windows登录失败怎么办