Boost 与qi::repeat和可选解析器不匹配
我一直在尝试使用Qi来解析一个简单的新行分隔符 顶点文件。采用以下格式(以我自己制作的易于阅读的符号表示):Boost 与qi::repeat和可选解析器不匹配,boost,boost-spirit,Boost,Boost Spirit,我一直在尝试使用Qi来解析一个简单的新行分隔符 顶点文件。采用以下格式(以我自己制作的易于阅读的符号表示): double可选(int可选(int))或(double可选(double)) 我的测试用例开始失败,重复,我找不到错误。代码中的注释希望更具启发性: #include <boost/spirit/include/qi.hpp> #include <string> #include <iostream> using namespace boost::
double可选(int可选(int))或(double可选(double))
我的测试用例开始失败,重复,我找不到错误。代码中的注释希望更具启发性:
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iostream>
using namespace boost::spirit;
qi::rule<std::string::iterator, ascii::space_type> vertexRule =
(double_ >> double_ >> double_);
qi::rule<std::string::iterator, ascii::space_type> colorRule =
(double_ >> double_ >> double_ >> -(double_)) | (uint_ >> uint_ >> uint_ >> -(uint_));
template<typename Iterator, typename Rule>
bool parseIt(Iterator begin, Iterator end, Rule rule) {
bool r = qi::phrase_parse(
begin, end,
rule,
ascii::space
);
if(begin != end) {
std::cout << "No full match!" << std::endl;
while(begin != end)
std::cout << *begin++;
return false;
}
return r;
}
int main()
{
qi::rule<std::string::iterator, ascii::space_type> rule1 =
repeat(3)[vertexRule >> -(colorRule)];
std::string t1{
"20.0 20.0 20.0\n"
"1.0 1.0 1.0 255 0 255 23\n"
"1.0 1.0 1.0 1.0 0.3 0.2 0.3\n"
};
std::cout << std::boolalpha;
// matches
std::cout << parseIt(t1.begin(), t1.end(), rule1) << std::endl;
// 3 double 3 ints
std::string test{"1.0 1.0 1.0 1 3 2\n"};
// matches individually
std::cout << parseIt(test.begin(), test.end(), vertexRule >> -(colorRule)) << std::endl;
// offending line added at the end
// but position does not matter
// also offending 3 double 3 double
std::string t2{
"20.0 20.0 20.0\n"
"1.0 1.0 1.0 255 0 255 23\n"
"1.0 1.0 1.0 1.0 0.3 0.2 0.3\n"
"1.0 1.0 1.0 1 3 2\n"
};
qi::rule<std::string::iterator, ascii::space_type> rule2 =
repeat(4)[vertexRule >> -(colorRule)];
// does not match
std::cout << parseIt(t2.begin(), t2.end(), rule2) << std::endl;
// interestingly this matches
// std::string t2{
// "1.0 1.0 1.0 1 3 2\n"
// "1.0 1.0 1.0 1 3 2\n"
// "1.0 1.0 1.0 1 3 2\n"
// "1.0 1.0 1.0 1 3 2\n"
// };
}
#包括
#包括
#包括
使用名称空间boost::spirit;
qi::规则顶点规则=
(双倍>>双倍>>双倍);
qi::规则颜色规则=
(双双)(双)(双)(双)(双)(双))(双;
模板
bool parseIt(迭代器开始、迭代器结束、规则){
bool r=qi::短语解析(
开始,结束,
规则,
ascii::空格
);
如果(开始!=结束){
std::cout你的散文描述和示例输入似乎表明行尾对你的语法有意义
然而,我找不到任何证据证明你试图在规则中表达这一点
另一个问题是double_
和uint_
之间的歧义(见下文)
这是一个重新制作的示例,它添加了一个自定义跳过程序(它不会吃掉eol
)。此外,我还使它接受任何数量的尾随eol
,但除此之外:
skipper = qi::char_(" \t");
bool r = qi::phrase_parse(
begin, end,
(vertexRule >> -colorRule) % qi::eol >> *qi::eol >> qi::eoi,
skipper
);
所有解析返回成功的完整代码:
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iostream>
using namespace boost::spirit;
template<typename Iterator>
bool parseIt(Iterator begin, Iterator end)
{
qi::rule<Iterator, qi::blank_type> vertexRule, colorRule;
vertexRule = double_ >> double_ >> double_;
colorRule = (double_ >> double_ >> double_ >> -(double_)) | (uint_ >> uint_ >> uint_ >> -(uint_));
bool r = qi::phrase_parse(
begin, end,
(vertexRule >> -colorRule) % qi::eol >> *qi::eol >> qi::eoi,
qi::blank
);
if(begin != end)
{
std::cout << "No full match! '" << std::string(begin, end) << std::endl;
return false;
}
return r;
}
int main()
{
std::string t1
{
"20.0 20.0 20.0\n"
"1.0 1.0 1.0 255 0 255 23\n"
"1.0 1.0 1.0 1.0 0.3 0.2 0.3\n"
};
std::cout << std::boolalpha;
// matches
std::cout << parseIt(t1.begin(), t1.end()) << std::endl;
// 3 double 3 ints
std::string test {"1.0 1.0 1.0 1 3 2\n"};
// matches individually
std::cout << parseIt(test.begin(), test.end()) << std::endl;
// offending line added at the end
// but position does not matter
// also offending 3 double 3 double
std::string t2
{
"20.0 20.0 20.0\n"
"1.0 1.0 1.0 255 0 255 23\n"
"1.0 1.0 1.0 1.0 0.3 0.2 0.3\n"
"1.0 1.0 1.0 1 3 2\n"
};
// does not match
std::cout << parseIt(t2.begin(), t2.end()) << std::endl;
// interestingly this matches
// std::string t2{
// "1.0 1.0 1.0 1 3 2\n"
// "1.0 1.0 1.0 1 3 2\n"
// "1.0 1.0 1.0 1 3 2\n"
// "1.0 1.0 1.0 1 3 2\n"
// };
}
目前,规则的(uint\u>>uint\u>>uint\u>>-(uint\u)
部分永远不会匹配,因为它也会匹配第一部分(使用双精度
)
colorRule = double_ >> double_ >> double_ >> -double_;
当然,除非将值指定为浮点数(例如,uint从0..255变为,而double从0.0..1.0变为)时,值的含义会发生变化。在这种情况下,我可以理解为什么要检测整型。可以通过重新排序来实现这一点
colorRule = (uint_ >> uint_ >> uint_ >> -(uint_))
| (double_ >> double_ >> double_ >> -(double_));
为了使解析器的用户更容易,我只需要在任何时候公开相同的属性类型,并考虑使用任何适当的转换来将整数转换为双倍的语义动作:
#include <boost/spirit/include/phoenix_operator.hpp>
// ....
qi::rule<Iterator, Skipper, double()> colorInt = uint_ [ _val = _1 / 255.0 ];
colorRule = (colorInt >> colorInt >> colorInt >> -(colorInt))
| (double_ >> double_ >> double_ >> -(double_));
#包括
// ....
qi::规则colorInt=uint_[\u val=\u 1/255.0];
colorRule=(colorInt>>colorInt>>colorInt>>-(colorInt))
|(双双)(双)(双)(双)(双));
我的印象是,新行是自动处理的,因为它在大多数运行中似乎都是有效的。显然我错了。对我来说,跳过仍然是最黑暗的精神领域之一。@pmr:跳过实际上太简单了;大多数人希望它能发挥神奇的作用,但事实并非如此:跳过者只会跳过所有跳过的内容(通常是空白)在解析器看到输入之前。查看qi::lexeme[]
(要禁用表达式的跳过),qi::raw[]
(要返回原始源迭代器,包括跳过的字符),qi::distinct
(来自Spirit存储库——要求在解析器边界处跳过)管理跳过程序。请注意,对于用户,例如qi::lexeme[]
内部的colorInt
,您必须从规则类型中删除跳过程序:)还有一件事:远离跳过程序意味着:在规则中提及每个跳过的标记,并使用qi::parse
而不是qi::parse\u短语
?
#include <boost/spirit/include/phoenix_operator.hpp>
// ....
qi::rule<Iterator, Skipper, double()> colorInt = uint_ [ _val = _1 / 255.0 ];
colorRule = (colorInt >> colorInt >> colorInt >> -(colorInt))
| (double_ >> double_ >> double_ >> -(double_));