2016-11-11 95 views
1

我已经编写了以下简单语法来检测服务器返回的字符串是否为失败登录。我在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

+0

“我意识到解析一个数字,如技术我应该写*(齐:: int_)” - 如果数字是不可选的,要么使用'齐:: uint_'或'+ qi :: digit'甚至'repeat(4)[digit]' – sehe

+0

对空白有好的想法。我几乎要提到它,但我对你的“语法”一无所知,并且不想使其复杂化 – sehe

回答

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; 
}; 

注意:使用补气::空间/齐::点燃和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

+0

非常详细的答案!谢谢! – joshu