aud*_*ric 7 c++ boost boost-spirit boost-spirit-qi
我对提升精神队长有困难.
我需要解析一个这样的文件:
ROW int
int [int, int]
int [int, int]
...
Run Code Online (Sandbox Code Playgroud)
只有在第一个int之后添加'_'时,我能够毫无问题地解析它(感谢stackoverflow;).
事实上,我认为船长在第一个int之后吃了行尾,所以第一个和第二个(在第二行)看起来只有一个int.我不明白如何保持eol但是吃空间.我找到了使用自定义解析器的示例,如此处和此处.
我尝试了qi :: blank,自定义解析器,单一规则点亮('')无论我使用什么队长,空间和eol总是吃.
我的语法是:
一行:
struct rowType
{
unsigned int number;
std::list<unsigned int> list;
};
Run Code Online (Sandbox Code Playgroud)
存储在结构中的完整问题:
struct problemType
{
unsigned int ROW;
std::vector<rowType> rows;
};
Run Code Online (Sandbox Code Playgroud)
行解析器:
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;
};
Run Code Online (Sandbox Code Playgroud)
和问题解析器:
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;
};
Run Code Online (Sandbox Code Playgroud)
我这样使用它:
main() {
static const problem_parser<spirit::multi_pass<base_iterator_type> > p;
...
spirit::qi::phrase_parse(first, last ,
p,
qi::space,
pb);
}
Run Code Online (Sandbox Code Playgroud)
当然,qi :: space是我的问题,解决我的问题的方法是不使用skipper,但是phrase_parse需要一个,然后我的解析器需要一个.
我现在被困了几个小时......我认为这是明显的我误解了.
谢谢你的帮助.
seh*_*ehe 11
通常,以下指令有助于抑制/切换中间语法中的队长:
qi::lexeme [ p ]
这会禁止一个队长,例如,如果你想确保解析一个没有内部跳过的标识符)
qi::raw [ p ]
它会像往常一样解析,包括跳过,但会返回匹配的源序列的原始迭代器范围(包括跳过的位置)
qi::no_skip [ p ]qi::skip(s) [ p ]s(注意你需要qi::rule<>在这样的skip[]子句中使用适当声明的实例)哪里p是任何解析器表达式.
正如您所知,您的问题可能是qi::space吃掉所有空白.我不可能知道你的语法有什么问题(因为你没有显示完整的语法或相关的输入).
因此,这就是我写的.注意
qi::eol以明确地要求在特定位置的换行符qi::blank作为船长的使用(不包括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";
}
Run Code Online (Sandbox Code Playgroud)
如果你真的不想要换行:
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";
}
Run Code Online (Sandbox Code Playgroud)
回应评论:这是一个片段,显示如何从文件中读取输入.经过测试,对我来说效果很好:
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;
Run Code Online (Sandbox Code Playgroud)