忽略给定单词的所有字符

时间:2017-04-11 21:33:32

标签: c++ boost boost-spirit

我有这个示例代码,它正确解析字符串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");
}

2 个答案:

答案 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'

测试仍然通过。

  

请注意,您的原始示例输入有一个尾随",您只需将其忽略。