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是不一致的。你可以大大简化。
#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
我编写了以下简单语法来检测服务器返回的字符串是否为登录失败。我在 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是不一致的。你可以大大简化。
#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