提振精神的队长问题 [英] Boost spirit skipper issues
问题描述
我有提振精神的船长麻烦。
I have trouble with boost spirit skippers.
我需要解析这样的文件:
I need to parse a file like that :
ROW int
int [int, int]
int [int, int]
...
我能够解析它没有问题(感谢StackOverflow的;)只有我的第一个INT后面加一个'_'。
I am able to parse it without problem (thanks to stackoverflow ;) only if I add an '_' after the first int.
其实,我觉得队长第一个吃INT后线的末端,所以第一和第二(在第二行)看起来像只有一个int值。我不明白如何保持停产,但吃的空间。我发现的例子使用像这里自定义解析器和这里。
In fact, I think the skipper eat the end of line after the first int, so the first and second (on second line) look as only one int. I don't understand how to keep eol but eat spaces. I've found examples to use a custom parser like here and here.
我试过气::空白,自定义分析器与一个单一的规则亮('')
不管我用什么队长,空间和EOL总是吃。
I tried qi::blank, custom parser with one single rule lit(' ') No matter what skipper I use, space and eol are always eat.
我的语法是:
行:
struct rowType
{
unsigned int number;
std::list<unsigned int> list;
};
存储在一个结构的完整的问题:
the full problem stored in a structure :
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);
}
当然,补气::空间是我的问题,并解决我的问题将不使用的队长一种方式,但phrase_parse需要一个,然后我的解析器要求之一。
Of course, the qi::space is my problem, and a way to solve my problem would be to don't use a skipper, but phrase_parse requires one, and then my parser requires one.
我现在因为几个小时卡住...
我认为这是显而易见的事我误解。
I'm stuck since some hours now... I think it's something obvious I have misunderstood.
感谢您的帮助。
推荐答案
在一般以下指令是用于抑制/开关船长中期语法帮助:
In general the following directives are helpful for inhibiting/switching skippers mid-grammar:
-
<一个href=\"http://www.boost.org/doc/libs/1_53_0/libs/spirit/doc/html/spirit/qi/reference/directive/lexeme.html\"><$c$c>qi::lexeme [P]
抑制一个队长,例如如果你想确保你解析没有内部跳过的标识符)
qi::lexeme [ p ]
which inhibits a skipper, e.g. if you want to be sure you parse an identifier without internal skips)
<一个href=\"http://www.boost.org/doc/libs/1_53_0/libs/spirit/doc/html/spirit/qi/reference/directive/raw.html\"><$c$c>qi::raw [P]
它解析像往常一样,包括跳跃,但返回匹配源序列的原始迭代器区间(包括跳过的位置)
qi::raw [ p ]
which parses like always, including skips, but returns the raw iterator range of the matched source sequence (including the skipped positions)
其中, P
是任何解析器前pression。
where p
is any parser expression.
您的问题,因为你已经知道了,可能是齐::空间
吃所有的空白。我不可能知道什么是错在你的语法(因为你不显示为完整的语法,或相关的输入)。
Your problem, as you already know, might be that qi::space
eats all whitespace. I can't possibly know what is wrong in your grammar (since you don't show either the full grammar, or relevant input).
因此,这里是我会写。注意
Therefore, here's what I'd write. Note
- 使用
齐:: EOL
到明确地的要求在特定的地点换行 - 使用
齐::空白
作为队长(不包括EOL
) 的 - 为简单起见我结合语法
- the use of
qi::eol
to explicitely require linebreaks at specific locations - the use of
qi::blank
as a skipper (not includingeol
) - for brevity I combined the grammars
code:
#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";
}
如果你真的不想要求换行:
If you really didn't want to require line breaks:
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";
}
更新
在回应评论:这里是一个片段,展示了如何从文件中读取输入。这是测试和对我工作得很好:
Update
In response to the comment: here is a snippet that shows how to read the input from a file. This was tested and works fine for me:
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;
这篇关于提振精神的队长问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!