我有这个示例代码,它正确解析字符串str
。
如果在字符串之前和/或之后有任何额外的字符,我该如何使它工作?例如,如果我did str = std::string("AAA") + str + std::string("AAA")
frame.h
#define BOOST_SPIRIT_USE_PHOENIX_V3
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
namespace ascii = boost::spirit::ascii;
struct frame
{
std::string addr;
std::string func;
std::string file;
std::string fullname;
std::string line;
std::map<std::string, std::string> kv;
};
template <typename Iterator>
struct argsArray : qi::grammar<Iterator, std::map<std::string, std::string>()>
{
argsArray() : argsArray::base_type(query)
{
query =
qi::lit("args=[") >> pair >> *(qi::lit(',') >> pair) >> qi::lit(']');
pair = qi::lit("{name=") >> quoted_string >> qi::lit(",value=") >>
quoted_string >> qi::lit("}");
key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
quoted_string %= boost::spirit::lexeme['"' >> +(qi::char_ - '"') >> '"'];
}
qi::rule<Iterator, std::map<std::string, std::string>()> query;
qi::rule<Iterator, std::pair<std::string, std::string>()> pair;
qi::rule<Iterator, std::string()> key;
qi::rule<Iterator, std::string()> quoted_string;
};
template <typename Iterator>
struct frameParser : qi::grammar<Iterator, frame(), ascii::space_type>
{
frameParser() : frameParser::base_type(frame_rule)
{
static const auto _addr = phx::bind(&frame::addr, qi::_r1);
static const auto _func = phx::bind(&frame::func, qi::_r1);
static const auto _file = phx::bind(&frame::file, qi::_r1);
static const auto _fullname = phx::bind(&frame::fullname, qi::_r1);
static const auto _line = phx::bind(&frame::line, qi::_r1);
static const auto _kv = phx::bind(&frame::kv, qi::_r1);
func = qi::lit("func=") >> quoted_string;
addr = qi::lit("addr=") >> quoted_string;
file = qi::lit("file=") >> quoted_string;
fullname = qi::lit("fullname=") >> quoted_string;
line = qi::lit("line=") >> quoted_string;
func_rule = func[_func = qi::_1];
addr_rule = addr[_addr = qi::_1];
file_rule = file[_file = qi::_1];
fullname_rule = fullname[_fullname = qi::_1];
line_rule = line[_line = qi::_1];
kv_rule = arrTest[_kv = qi::_1];
quoted_string %= boost::spirit::lexeme['"' >> +(qi::char_ - '"') >> '"'];
frame_rule = qi::lit("frame={") >>
(addr_rule(qi::_val) ^ qi::lit(',') ^ func_rule(qi::_val) ^
qi::lit(',') ^ file_rule(qi::_val) ^ qi::lit(',') ^
fullname_rule(qi::_val) ^ qi::lit(',') ^ line_rule(qi::_val) ^
qi::lit(',') ^ kv_rule(qi::_val)) >>
qi::lit('}');
BOOST_SPIRIT_DEBUG_NODES(
(frame_rule)(func_rule)(addr_rule)(fullname_rule)(line_rule))
}
qi::rule<Iterator, void(frame&), ascii::space_type> func_rule, addr_rule,
file_rule, fullname_rule, line_rule, kv_rule;
qi::rule<Iterator, frame(), ascii::space_type> frame_rule;
qi::rule<Iterator, std::string()> addr, func, file, fullname, line;
qi::rule<Iterator, std::string()> quoted_string;
argsArray<Iterator> arrTest;
};
test.cc
#include <iostream>
#include "gtest/gtest.h"
#include "parser/frame.h"
TEST(ParseFrameString, Test1)
{
std::string str = R"(frame={addr="0x0000000000414008",)"
R"(func="main",)"
R"(args=[{name="argc",value="1"},)"
R"({name="argv",value="0x7fffffffe1a8"}],)"
R"(file="/home/stiopa/development/gdbFront/main.cc",)"
R"(fullname="/home/stiopa/development/gdbFront/main.cc",)"
R"(line="90"}")";
typedef std::string::const_iterator It;
const frameParser<It> g;
It iter(str.begin()), end(str.end());
frame frame;
bool r = phrase_parse(iter, end, g, boost::spirit::ascii::space, frame);
EXPECT_EQ(r, true);
EXPECT_EQ(frame.addr, "0x0000000000414008");
EXPECT_EQ(frame.func, "main");
std::map<std::string, std::string> kv{{"argc", "1"},
{"argv", "0x7fffffffe1a8"}};
EXPECT_EQ(frame.kv, kv);
EXPECT_EQ(frame.file, "/home/stiopa/development/gdbFront/main.cc");
EXPECT_EQ(frame.fullname, "/home/stiopa/development/gdbFront/main.cc");
EXPECT_EQ(frame.line, "90");
}
答案 0 :(得分:2)
简单,低技术的解决方案是使用存储库中的qi::seek
:
#include <boost/spirit/repository/include/qi_seek.hpp>
namespace qir = boost::spirit::repository::qi;
然后:
bool r = phrase_parse(iter, end, qir::seek[g], boost::spirit::ascii::space, frame);
<强> Live On Coliru 强>
#define BOOST_SPIRIT_USE_PHOENIX_V3
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/repository/include/qi_seek.hpp>
namespace qi = boost::spirit::qi;
namespace qir = boost::spirit::repository::qi;
namespace phx = boost::phoenix;
namespace ascii = boost::spirit::ascii;
struct frame
{
std::string addr;
std::string func;
std::string file;
std::string fullname;
std::string line;
std::map<std::string, std::string> kv;
};
template <typename Iterator>
struct argsArray : qi::grammar<Iterator, std::map<std::string, std::string>()>
{
argsArray() : argsArray::base_type(query)
{
query =
qi::lit("args=[") >> pair >> *(qi::lit(',') >> pair) >> qi::lit(']');
pair = qi::lit("{name=") >> quoted_string >> qi::lit(",value=") >>
quoted_string >> qi::lit("}");
key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
quoted_string %= boost::spirit::lexeme['"' >> +(qi::char_ - '"') >> '"'];
}
qi::rule<Iterator, std::map<std::string, std::string>()> query;
qi::rule<Iterator, std::pair<std::string, std::string>()> pair;
qi::rule<Iterator, std::string()> key;
qi::rule<Iterator, std::string()> quoted_string;
};
template <typename Iterator>
struct frameParser : qi::grammar<Iterator, frame(), ascii::space_type>
{
frameParser() : frameParser::base_type(frame_rule)
{
static const auto _addr = phx::bind(&frame::addr, qi::_r1);
static const auto _func = phx::bind(&frame::func, qi::_r1);
static const auto _file = phx::bind(&frame::file, qi::_r1);
static const auto _fullname = phx::bind(&frame::fullname, qi::_r1);
static const auto _line = phx::bind(&frame::line, qi::_r1);
static const auto _kv = phx::bind(&frame::kv, qi::_r1);
func = qi::lit("func=") >> quoted_string;
addr = qi::lit("addr=") >> quoted_string;
file = qi::lit("file=") >> quoted_string;
fullname = qi::lit("fullname=") >> quoted_string;
line = qi::lit("line=") >> quoted_string;
func_rule = func[_func = qi::_1];
addr_rule = addr[_addr = qi::_1];
file_rule = file[_file = qi::_1];
fullname_rule = fullname[_fullname = qi::_1];
line_rule = line[_line = qi::_1];
kv_rule = arrTest[_kv = qi::_1];
quoted_string %= boost::spirit::lexeme['"' >> +(qi::char_ - '"') >> '"'];
frame_rule = qi::lit("frame={") >>
(addr_rule(qi::_val) ^ qi::lit(',') ^ func_rule(qi::_val) ^
qi::lit(',') ^ file_rule(qi::_val) ^ qi::lit(',') ^
fullname_rule(qi::_val) ^ qi::lit(',') ^ line_rule(qi::_val) ^
qi::lit(',') ^ kv_rule(qi::_val)) >>
qi::lit('}');
BOOST_SPIRIT_DEBUG_NODES(
(frame_rule)(func_rule)(addr_rule)(fullname_rule)(line_rule))
}
qi::rule<Iterator, void(frame&), ascii::space_type> func_rule, addr_rule,
file_rule, fullname_rule, line_rule, kv_rule;
qi::rule<Iterator, frame(), ascii::space_type> frame_rule;
qi::rule<Iterator, std::string()> addr, func, file, fullname, line;
qi::rule<Iterator, std::string()> quoted_string;
argsArray<Iterator> arrTest;
};
#include <iostream>
//#include "parser/frame.h"
int main()
{
std::string str = R"(frame={addr="0x0000000000414008",)"
R"(func="main",)"
R"(args=[{name="argc",value="1"},)"
R"({name="argv",value="0x7fffffffe1a8"}],)"
R"(file="/home/stiopa/development/gdbFront/main.cc",)"
R"(fullname="/home/stiopa/development/gdbFront/main.cc",)"
R"(line="90"}")";
str = "AAA" + str + "AAA";
typedef std::string::const_iterator It;
const frameParser<It> g;
It iter(str.begin()), end(str.end());
frame frame;
bool r = phrase_parse(iter, end, qir::seek[g], boost::spirit::ascii::space, frame);
assert(r == true);
assert(frame.addr == "0x0000000000414008");
assert(frame.func == "main");
std::map<std::string, std::string> kv{{"argc", "1"},
{"argv", "0x7fffffffe1a8"}};
assert(frame.kv == kv);
assert(frame.file == "/home/stiopa/development/gdbFront/main.cc");
assert(frame.fullname == "/home/stiopa/development/gdbFront/main.cc");
assert(frame.line == "90");
}
测试仍然通过。
答案 1 :(得分:1)
这是一个免费的代码审查。请参阅
','
。您必须要求它,除非帧末('}')。您不能连续接受多个<强> Live On Coliru 强>
#define BOOST_SPIRIT_USE_PHOENIX_V3
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/repository/include/qi_seek.hpp>
namespace qi = boost::spirit::qi;
namespace qir = boost::spirit::repository::qi;
namespace phx = boost::phoenix;
namespace ascii = boost::spirit::ascii;
struct frame {
std::string addr;
std::string func;
std::string file;
std::string fullname;
std::string line;
std::map<std::string, std::string> kv;
};
BOOST_FUSION_ADAPT_STRUCT(frame, addr, func, file, fullname, line, kv)
template <typename Iterator>
struct argsArray : qi::grammar<Iterator, std::map<std::string, std::string>()>
{
argsArray() : argsArray::base_type(query)
{
query = "args=[" >> pair >> *(',' >> pair) >> ']';
pair = "{name=" >> quoted_string >> ",value=" >> quoted_string >> "}";
key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
quoted_string = '"' >> +(qi::char_ - '"') >> '"';
}
private:
qi::rule<Iterator, std::map<std::string, std::string>()> query;
qi::rule<Iterator, std::pair<std::string, std::string>()> pair;
qi::rule<Iterator, std::string()> key;
qi::rule<Iterator, std::string()> quoted_string;
};
template <typename Iterator>
struct frameParser : qi::grammar<Iterator, frame(), ascii::space_type>
{
frameParser() : frameParser::base_type(frame_rule)
{
quoted_string = '"' >> +(qi::char_ - '"') >> '"';
delim = (&qi::lit('}')) | ',';
field_rule = qi::lexeme [ qi::lit(qi::_r1) >> '=' ] >> quoted_string >> delim;
kv_rule = arrTest >> delim;
frame_rule = "frame={" >>
(field_rule(+"addr") ^
field_rule(+"func") ^
field_rule(+"file") ^
field_rule(+"fullname") ^
field_rule(+"line") ^
kv_rule
) >> '}';
BOOST_SPIRIT_DEBUG_NODES((frame_rule)(field_rule))
}
private:
qi::rule<Iterator> delim;
qi::rule<Iterator, std::string(char const*), ascii::space_type> field_rule;
qi::rule<Iterator, std::map<std::string, std::string>()> kv_rule;
qi::rule<Iterator, frame(), ascii::space_type> frame_rule;
qi::rule<Iterator, std::string()> quoted_string;
argsArray<Iterator> arrTest;
};
#include <iostream>
//#include "parser/frame.h"
int main()
{
std::string str = R"(frame={addr="0x0000000000414008",)"
R"(func="main",)"
R"(args=[{name="argc",value="1"},)"
R"({name="argv",value="0x7fffffffe1a8"}],)"
R"(file="/home/stiopa/development/gdbFront/main.cc",)"
R"(fullname="/home/stiopa/development/gdbFront/main.cc",)"
R"(line="90"}")";
str = "AAA" + str + "AAA";
typedef std::string::const_iterator It;
const frameParser<It> g;
It iter(str.begin()), end(str.end());
frame frame;
bool r = phrase_parse(iter, end, qir::seek[g], boost::spirit::ascii::space, frame);
if (iter != end)
std::cout << "Remaining unparsed: '" << std::string(iter,end) << "'\n";
assert(r == true);
assert(frame.addr == "0x0000000000414008");
assert(frame.func == "main");
std::map<std::string, std::string> kv{{"argc", "1"},
{"argv", "0x7fffffffe1a8"}};
assert(frame.kv == kv);
assert(frame.file == "/home/stiopa/development/gdbFront/main.cc");
assert(frame.fullname == "/home/stiopa/development/gdbFront/main.cc");
assert(frame.line == "90");
}
打印:
Remaining unparsed: '"AAA'
测试仍然通过。
请注意,您的原始示例输入有一个尾随
"
,您只需将其忽略。