[英]Boost spirit skipper issues
我在提升精神船長方面遇到了麻煩。
我需要解析這樣的文件:
ROW int
int [int, int]
int [int, int]
...
只有當我在第一個 int 之后添加一個“_”時,我才能毫無問題地解析它(感謝 stackoverflow ;)。
事實上,我認為船長在第一個 int 之后吃掉了行尾,所以第一個和第二個(在第二行)看起來只有一個 int。 我不明白如何保持 eol 但吃空間。 我找到了使用自定義解析器的示例,例如here和here 。
我嘗試了 qi::blank,一個單一規則的自定義解析器 lit(' ') 無論我使用什么船長,空間和 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 是我的問題,解決我的問題的一種方法是不使用船長,但phrase_parse需要一個,然后我的解析器需要一個。
我已經被困了幾個小時了......我認為這很明顯我誤解了。
謝謝你的幫助。
通常,以下指令有助於在語法中禁止/切換跳過者:
qi::lexeme [ p ]
這會禁止船長,例如,如果您想確保在沒有內部跳過的情況下解析標識符) - 另請參閱no_skip
進行比較
qi::raw [ p ]
它像往常一樣解析,包括跳過,但返回匹配源序列的原始迭代器范圍(包括跳過的位置)
qi::no_skip [ p ]
在沒有預先跳過的情況下禁止跳過(我創建了一個最小的例子來證明這里的區別: Boost Spirit lexeme vs no_skip )
qi::skip(s) [ p ]
它完全用另一個 skipper s
替換了 skipper (請注意,您需要在這樣的skip[]
子句中使用適當聲明的qi::rule<>
實例)
其中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";
}
如果你真的不想要求換行:
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;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.