2016-11-11 74 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