gpt4 book ai didi

c++ - boost spirit skipper 问题

转载 作者:太空宇宙 更新时间:2023-11-04 12:56:41 25 4
gpt4 key购买 nike

我在使用 boost spirit skippers 时遇到了麻烦。

我需要像这样解析一个文件:

ROW int
int [int, int]
int [int, int]
...

我能够毫无问题地解析它(感谢 stackoverflow ;)只有当我在第一个 int 之后添加一个 '_' 时。

事实上,我认为 skipper 在第一个 int 之后吃掉行尾,所以第一个和第二个(在第二行)看起来只有一个 int。我不明白如何保持 eol 但吃空间。我找到了使用自定义解析器的示例,例如 herehere .

我尝试了 qi::blank,一个带有一条规则的自定义解析器 lit(' ')不管我用什么 skipper,space 和 eol 总是吃。

我的语法是:

一行:

struct rowType
{
unsigned int number;
std::list<unsigned int> list;
};

存储在结构中的完整问题:

struct problemType
{
unsigned int ROW;
std::vector<rowType> rows;
};

行解析器:

template<typename Iterator>
struct row_parser : qi::grammar<Iterator, rowType(), qi::space_type>
{
row_parser() : row_parser::base_type(start)
{

list = '[' >> -(qi::int_ % ',') >> ']';
start = qi::int_ >> list;
}

qi::rule<Iterator, rowType(), qi::space_type> start;
qi::rule<Iterator, std::list<unsigned int>(), qi::space_type> list;
};

和问题解析器:

template<typename Iterator>
struct problem_parser : qi::grammar<Iterator,problemType(),qi::space_type>
{

problem_parser() : problem_parser::base_type(start)
{
using boost::phoenix::bind;
using qi::lit;

start = qi::int_ >> lit('_') >> +(row);

//BOOST_SPIRIT_DEBUG_NODE(start);
}

qi::rule<Iterator, problemType(),qi::space_type> start;
row_parser<Iterator> row;
};

我是这样使用它的:

main() {
static const problem_parser<spirit::multi_pass<base_iterator_type> > p;
...
spirit::qi::phrase_parse(first, last ,
p,
qi::space,
pb);
}

当然,qi::space 是我的问题,解决我的问题的方法是不使用 skipper,但是 phrase_parse 需要一个,然后我的解析器需要一个。

我被困了几个小时了...我认为这很明显是我误解了。

感谢您的帮助。

最佳答案

一般来说,以下指令有助于在语法中途抑制/切换跳过者:

  • qi::lexeme [ p ]
    这会抑制 skipper ,例如如果你想确保在没有内部跳过的情况下解析标识符) - 另请参阅 no_skip用于比较

  • qi::raw [ p ]
    像往常一样解析,包括跳过,但返回匹配源序列的原始迭代器范围(包括跳过的位置)

  • qi::no_skip [ p ]
    在没有预跳过的情况下禁止跳过(我创建了一个最小的例子来演示这里的区别:Boost Spirit lexeme vs no_skip)

  • qi::skip(s) [ p ]
    用另一个 skipper 代替 skipper s完全(请注意,您需要在这样的 qi::rule<> 子句中使用适当声明的 skip[] 实例)

哪里p是任何解析器表达式。

具体解决方案

如您所知,您的问题可能是 qi::space吃掉 所有 空格。我不可能知道你的语法有什么问题(因为你既没有显示完整的语法,也没有显示相关的输入)。

因此,这就是我要写的内容。注意

  • 使用 qi::eol 明确要求在特定位置换行
  • 使用qi::blank作为 skipper (不包括 eol )
  • 为简洁起见,我合并了语法

代码:

#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

struct rowType {
unsigned int number;
std::list<unsigned int> list;
};

struct problemType {
unsigned int ROW;
std::vector<rowType> rows;
};

BOOST_FUSION_ADAPT_STRUCT(rowType, (unsigned int, number)(std::list<unsigned int>, list))
BOOST_FUSION_ADAPT_STRUCT(problemType, (unsigned int, ROW)(std::vector<rowType>, rows))

template<typename Iterator>
struct problem_parser : qi::grammar<Iterator,problemType(),qi::blank_type>
{
problem_parser() : problem_parser::base_type(problem)
{
using namespace qi;
list = '[' >> -(int_ % ',') >> ']';
row = int_ >> list >> eol;
problem = "ROW" >> int_ >> eol >> +row;

BOOST_SPIRIT_DEBUG_NODES((problem)(row)(list));
}

qi::rule<Iterator, problemType() , qi::blank_type> problem;
qi::rule<Iterator, rowType() , qi::blank_type> row;
qi::rule<Iterator, std::list<unsigned int>(), qi::blank_type> list;
};

int main()
{
const std::string input =
"ROW 1\n"
"2 [3, 4]\n"
"5 [6, 7]\n";

auto f = begin(input), l = end(input);

problem_parser<std::string::const_iterator> p;
problemType data;

bool ok = qi::phrase_parse(f, l, p, qi::blank, data);

if (ok) std::cout << "success\n";
else std::cout << "failed\n";

if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}

如果您真的不想要求换行符:

template<typename Iterator>
struct problem_parser : qi::grammar<Iterator,problemType(),qi::space_type>
{
problem_parser() : problem_parser::base_type(problem)
{
using namespace qi;
list = '[' >> -(int_ % ',') >> ']';
row = int_ >> list;
problem = "ROW" >> int_ >> +row;

BOOST_SPIRIT_DEBUG_NODES((problem)(row)(list));
}

qi::rule<Iterator, problemType() , qi::space_type> problem;
qi::rule<Iterator, rowType() , qi::space_type> row;
qi::rule<Iterator, std::list<unsigned int>(), qi::space_type> list;
};

int main()
{
const std::string input =
"ROW 1 " // NOTE whitespace, obviously required!
"2 [3, 4]"
"5 [6, 7]";

auto f = begin(input), l = end(input);

problem_parser<std::string::const_iterator> p;
problemType data;

bool ok = qi::phrase_parse(f, l, p, qi::space, data);

if (ok) std::cout << "success\n";
else std::cout << "failed\n";

if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}

更新

作为对评论的回应:这是一个片段,展示了如何从文件中读取输入。这已经过测试并且对我来说工作正常:

std::ifstream ifs("input.txt"/*, std::ios::binary*/);
ifs.unsetf(std::ios::skipws);

boost::spirit::istream_iterator f(ifs), l;

problem_parser<boost::spirit::istream_iterator> p;

关于c++ - boost spirit skipper 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46221217/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com