我正在使用增强精神来分析基于行的格式,其中允许空行。为此,我使用类似于以下语法的内容:
struct parser_type : public qi::grammar<std::string::iterator, qi::ascii::blank_type, std::vector<int>()>
{
typedef std::string::iterator Iterator;
parser_type() : parser_type::base_type(main)
{
element = qi::int_;
line %= element | qi::eps;
main %= +(line >> qi::eol);
}
qi::rule<Iterator, int()> element;
qi::rule<Iterator, qi::ascii::blank_type, int()> line;
qi::rule<Iterator, qi::ascii::blank_type, std::vector<int>()> main;
} parser;
这很好,因为qi::eps
和qi::eol
一起匹配空行。很好(尽管我愿意接受其他可能更好的方法来解析带空行的基于行的格式)。但是,line
解析器的属性是int
,显然它不存在于空行中。因此,对于
1
4
解析器创建一个向量,内容为{ 1, 0, 0, 4 }
。
我希望该行被完全忽略,也就是说,我不希望构造任何虚拟对象来匹配该行的属性。能做到吗?有没有更好的解析行的方法?
这是一个完整的最小示例(程序需要一个名为“ input”的输入文件,您可以使用上面的示例):
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
struct parser_type : public qi::grammar<std::string::iterator, qi::ascii::blank_type, std::vector<int>()>
{
typedef std::string::iterator Iterator;
parser_type() : parser_type::base_type(main)
{
element = qi::int_;
line = element | qi::eps;
main %= +(line >> qi::eol);
}
qi::rule<Iterator, int()> element;
qi::rule<Iterator, qi::ascii::blank_type, int()> line;
qi::rule<Iterator, qi::ascii::blank_type, std::vector<int>()> main;
} parser;
int main()
{
std::ifstream file("input");
std::stringstream buffer;
buffer << file.rdbuf();
std::string str = buffer.str();
auto iter = str.begin();
std::vector<int> lines;
bool r = qi::phrase_parse(iter, str.end(), parser, qi::ascii::blank, lines);
if (r && iter == str.end())
{
std::cout << "parse succeeded\n";
for(auto e : lines)
{
std::cout << e << '\n';
}
}
else
{
std::cout << "parse failed. Remaining unparsed: " << std::string(iter, str.end()) << '\n';
}
}
答案 0 :(得分:1)
此规则:
line = element | eps;
使您失去所需的信息。通过接受不匹配(eps
),您可以强制它只返回声明的值初始化属性(rul签名中的int
)。
因此,删除它,然后我通常使用列表运算符(%
)进行这种重复:
line = element;
main = -line % qi::eol;
这有效:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
struct parser_type : public qi::grammar<std::string::iterator, qi::ascii::blank_type, std::vector<int>()>
{
typedef std::string::iterator Iterator;
parser_type() : parser_type::base_type(main)
{
element = qi::int_;
line = element;
main = -line % qi::eol;
}
qi::rule<Iterator, int()> element;
qi::rule<Iterator, qi::ascii::blank_type, int()> line;
qi::rule<Iterator, qi::ascii::blank_type, std::vector<int>()> main;
} parser;
int main()
{
std::ifstream file("input");
std::stringstream buffer;
buffer << file.rdbuf();
std::string str = buffer.str();
auto iter = str.begin();
std::vector<int> lines;
bool r = qi::phrase_parse(iter, str.end(), parser, qi::ascii::blank, lines);
if (r && iter == str.end())
{
std::cout << "parse succeeded\n";
for(auto e : lines)
{
std::cout << e << '\n';
}
}
else
{
std::cout << "parse failed. Remaining unparsed: " << std::string(iter, str.end()) << '\n';
}
}
打印
parse succeeded
1
4