用替代操作员提升精神 '|' 失败!当有两个可能的规则要走时
boost spirit with alternative operator '|' Fail! when there are two possibles rules to go
我正在开发一个http解析器。当我尝试使用替代运算符进行解析时,它发现了一个问题。我可以使用hold[]修复属性中的值,而不是属性中的这些值。当在规则这里有一些简单的规则来证明我的问题;
qi::rule<string_iterator> some_rule(
(char_('/') >> *char_("0-9")) /*first rule accept /123..*/
| (char_('/') >> *char_("a-z")) /*second rule accept /abc..*/
);
然后我使用qi::parse
解析这个规则,如果输入字符串喜欢,它将失败;"/abcd"
然而,当我在第一条规则之前切换第二条规则时。解析器将返回true我认为问题是因为当解析器使用第一条规则的输入时然后它发现第一条规则是Fail。它不会回到第二条规则第一条规则的替代方案。
我试图将hold[]
放在第一条规则中,但它只对生成属性有帮助。它无法解决此问题。我不知道如何解决这个问题,因为HTTP有很多规则的开头是他们和其他人一样的规则。
===============有关我的代码的详细信息=========================
这是我解析字符串的函数
typedef std::string::const_iterator string_iterator;
typedef qi::rule<string_iterator, std::string()> rules_t;
void parse_to_string(const std::string& s, rules_t& r, std::string& result)
{
using namespace rule;
using qi::parse;
std::string::const_iterator iter = s.begin();
std::string::const_iterator end = s.end();
bool err = parse(iter, end, r, result);
if ( err && (iter==end) )
{
std::cout << "[correct]" << result << std::endl;
}
else
{
std::cout << "[incorrect]" << s << std::endl;
std::cout << "[dead with]" << result << std::endl;
}
}
总的来说,我有这个代码;
std::string result;
result = "";
str = "/htmlquery?";
qi::rule<string_iterator, std::string()> rule_wo_question( char_('/') >> *char_("a-z"));
qi::rule<string_iterator, std::string()> rule_w_question( char_('/') >> *char_("a-z") >> char_('?'));
qi::rule<string_iterator, std::string()> whatever_rule( rule_wo_question
| rule_w_question
);
parse_to_string(str, whatever_rule, result);
我得到了这个结果;
[不正确]/htmlquery?[dead with]/htmlquery<=你可以看到它不能消耗"?">
然而,当我像这样切换规则时;(我在"rule_wo_question"之前加了"rule_w_question"(
std::string result;
result = "";
str = "/htmlquery?";
qi::rule<string_iterator, std::string()> rule_wo_question( char_('/') >> *char_("a-z"));
qi::rule<string_iterator, std::string()> rule_w_question( char_('/') >> *char_("a-z") >> char_('?'));
qi::rule<string_iterator, std::string()> whatever_rule( rule_w_question
| rule_wo_question
);
parse_to_string(str, whatever_rule, result);
输出将为;[correct]/htmlquery?
第一个版本(错误的版本(看起来像是解析消费'/htmlquery'("rule_wo_question"(,然后它发现它不能消费'?'这使得这个规则失效。则此规则不能转到其他规则("rule_w_question"(。最后程序返回"[错误]">
第二个版本我把"rule_wo_question"改为"rule_wo_question"。这就是解析器返回"[correct]"作为结果的原因。
==============================================================我的整个代码与pthread和boost_filesystem链接的boost1.47这是我的主要.c
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/network/protocol.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/bind.hpp>
#include <boost/spirit/include/qi_uint.hpp>
using namespace boost::spirit::qi;
namespace qi = boost::spirit::qi;
typedef std::string::const_iterator string_iterator;
typedef qi::rule<string_iterator, std::string()> rules_t;
void parse_to_string(const std::string& s, rules_t& r, std::string& result)
{
using qi::parse;
std::string::const_iterator iter = s.begin();
std::string::const_iterator end = s.end();
bool err = parse(iter, end, r, result);
if ( err && (iter==end) )
{
std::cout << "[correct]" << result << std::endl;
}
else
{
std::cout << "[incorrect]" << s << std::endl;
std::cout << "[dead with]" << result << std::endl;
}
}
int main()
{
std::string str, result;
result = "";
str = "/htmlquery?";
qi::rule<string_iterator, std::string()> rule_wo_question( char_('/') >> *char_("a-z"));
qi::rule<string_iterator, std::string()> rule_w_question( char_('/') >> *char_("a-z") >> char_('?'));
qi::rule<string_iterator, std::string()> whatever_rule( rule_wo_question
| rule_w_question
);
parse_to_string(str, whatever_rule, result);
return 0;
}
结果是
[incorrect]/htmlquery?
[dead with]/htmlquery
Spirit在指定的序列中尝试给定的替代方案,并在匹配第一个后停止解析。没有进行详尽的匹配。如果有一个备选方案匹配,它就会停止寻找。IOW,备选方案的顺序很重要。你应该总是先列出"最长"的备选方案。
你为什么不这么做?
some_rule(
char_('/')
>> (
*char_("0-9") /*first rule accept /123..*/
| *char_("a-z") /*second rule accept/abc..*/
)
);
编辑:实际上,这将匹配/
,后面跟着空("0-9"0次(,并且不需要查找"a-z",请将*
更改为+
。
qi::rule<string_iterator> some_rule(
(char_('/') >> *char_("0-9")) >> qi::eol /*first rule accept /123..*/
| (char_('/') >> *char_("a-z")) >> qi::eol /*second rule accept /abc..*/
);
您可以使用","或其他终止符来代替eol
。问题是char_('/') >> *char_("0-9"))
与后面跟有0个或多个数字的"/"匹配。因此,"/abcd"与"/"匹配,然后停止解析。K-ballo的解决方案是我处理此案的方式,但如果(出于某种原因(他的解决方案不可接受,则提供该解决方案作为替代方案。
这是因为你的第一条规则匹配,Spirit是贪婪的。
(char_('/') >> *char_("0-9"))
将"/abcd"输入该规则将产生以下逻辑:
- "/abcd"->"/"是下一个字符吗?对子规则匹配。->"abcd"仍然存在
- "abcd"->是否有0位或更多数字?对有0位数字。子规则匹配。->"abcd"仍然存在
- alternative('|'(语句的第一个子句匹配;跳过剩余的备用子句。->"abcd"仍然存在
- 规则与剩余的"abcd"匹配。这可能会导致无法解析并导致您失败
您可以考虑将表示"0或更多"的"*"更改为表示"1或更多"。
- 如何在C++中从两个单独的for循环中添加两个数组
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 当在同一名称空间中有两个具有相同签名的函数时,会发生什么
- 如何返回一个类的两个对象相加的结果
- 如何在C++中将一个无符号的 int 转换为两个无符号的短裤?
- 如何将两个不同矢量的同一位置的两个元素组合在一起
- 两个字符串在 c++ 中不相等
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 两个文件使用彼此的功能-如何解决
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 如何确保在使用基于布尔值的两个方法之一调用方法时避免分支预测错误
- 停止cmake target_link_libraries将插件中静态库的两个对象文件链接到静态库本身
- 将fold表达式与std::一起用于两个元组
- 如何在C++中比较两个char数组
- 给定两个偶数,求出它们之间所有偶数的平方和
- C++ 如何将两个 makefile 对象目标规则(位于另一个文件夹中)合并到一个目标/规则中?
- 如何在yacc联合中保存出现在同一规则下的两个相同类型的对象
- 在不同的翻译单元中的两个变量违反了一个定义规则
- 一个定义规则和两个翻译单元中不同的类定义
- 用替代操作员提升精神 '|' 失败!当有两个可能的规则要走时