【发布时间】:2014-01-23 07:19:07
【问题描述】:
我正在尝试使用特殊规则解析 URL 查询字符串。到目前为止,它适用于下面描述的一个排除项 使用以下方法将 URL 解析为一组键值对:
const qi::rule<std::string::const_iterator, std::string()> key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9/%\\-_~\\.");
const qi::rule<std::string::const_iterator, std::string()> value = *(qi::char_ - '=' - '&');
const qi::rule<std::string::const_iterator, std::pair<std::string, std::string>()> pair = key >> -('=' >> value);
const qi::rule<std::string::const_iterator, std::unordered_map<std::string, std::string>()> query = pair >> *(('&') >> pair);
到目前为止,一切都很好。一种特殊情况,它可以以 XML 实体的形式呈现 & 符号 - & 因此查询规则升级为
const qi::rule<std::string::const_iterator, std::unordered_map<std::string, std::string>()> query = pair >> *((qi::lit("&")|'&') >> pair);
它按预期工作。然后出现了额外的特殊情况 - 引用的值可以包含未转义的等号和&符号,形式为 a=b&d=e&f=$$g=h&i=j$$&x=y&z=def 应该解析成
- a => b
- d => e
- f => g=h&i=j
- x => y
- x => 定义
所以我为“引用”值添加了附加规则
const qi::rule<std::string::const_iterator, std::string()> key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9/%\\-_~\\.");
const qi::rule<std::string::const_iterator, std::string()> escapedValue = qi::omit["$$"] >> *(qi::char_ - '$') >> qi::omit["$$"];
const qi::rule<std::string::const_iterator, std::string()> value = *(escapedValue | (qi::char_ - '=' - '&'));
const qi::rule<std::string::const_iterator, std::pair<std::string, std::string>()> pair = key >> -('=' >> value);
const qi::rule<std::string::const_iterator, std::unordered_map<std::string, std::string>()> query = pair >> *((qi::lit("&")|'&') >> pair);
它再次按预期工作,直到下一个案例 - a=b&d=e&f=$$g=h&i=j$$x=y&z=def,注意,关闭 "$$" 和下一个之间没有和号键名。看起来可以通过添加kleene运算符来轻松解决
const qi::rule<std::string::const_iterator, std::unordered_map<std::string, std::string>()> query = pair >> *(__*__(qi::lit("&")|'&') >> pair);
但由于某种原因,它不能解决问题。任何建议将不胜感激!
编辑: 示例代码
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <unordered_map>
namespace rulez
{
using namespace boost::spirit::qi;
using It = std::string::const_iterator;
const rule<It, std::string()> key = boost::spirit::qi::char_("a-zA-Z_") >> *boost::spirit::qi::char_("a-zA-Z_0-9/%\\-_~\\.");
const rule<It, std::string()> escapedValue = boost::spirit::qi::omit["$$"] >> *(boost::spirit::qi::char_ - '$') >> boost::spirit::qi::omit["$$"];
const rule<It, std::string()> value = *(escapedValue | (boost::spirit::qi::char_ - '=' - '&'));
const rule<It, std::pair<std::string, std::string>()> pair = key >> -('=' >> value);
const rule<It, std::unordered_map<std::string, std::string>()> query = pair >> *(*(boost::spirit::qi::lit("&")|'&') >> pair);
}
int main()
{
using namespace std;
unordered_map<string, string> keyVal;
//string const paramString = "a=b&d=e&f=$$g=h&i=j$$&x=y&z=def";
string const paramString = "a=b&d=e&f=$$g=h&i=j$$x=y&z=def";
boost::spirit::qi::parse(paramString.begin(), paramString.end(), rulez::query, keyVal);
for (const auto& pair : keyVal)
cout << "(\"" << pair.first << "\",\"" << pair.second << "\")" << endl;
}
“a=b&d=e&f=$$g=h&i=j$$x=y&z=def”的输出(错误,应该与“a=b&d=e&f=$$g=h&i=j $$&x=y&z=def")
("a", "b"),("d", "e"),("f", "g=h&i=jx")
“a=b&d=e&f=$$g=h&i=j$$&x=y&z=def”的输出(如预期)
("a", "b"),("d", "e"),("f", "g=h&i=j"),("x", "y"),("z ", "定义")
编辑: 更简单的解析规则,只是为了让东西更容易理解
namespace rulez
{
const rule<std::string::const_iterator, std::string()> key = +(char_ - '&' - '=');
const rule<std::string::const_iterator, std::string()> escapedValue = omit["$$"] >> *(char_ - '$') >> omit["$$"];
const rule<std::string::const_iterator, std::string()> value = *(escapedValue | (char_ - '&' - '='));
const rule<std::string::const_iterator, pair<std::string, std::string>()> pair = key >> -('=' >> value);
const rule<std::string::const_iterator, unordered_map<std::string, std::string>()> query = pair >> *(*(lit('&')) >> pair);
}
【问题讨论】:
-
提供可编译的示例(例如this)时更容易获得帮助。我不确定我是否理解您的意图,您期望的地图是
map={{a,b}, {d,e}, {f,g=h&i=j}, {x,y}, {z,def}};吗? -
你的
value规则应该是escapedValue|"unescapedValue",对吧?因为你现在拥有的是不同的。 -
不,情况有点复杂,有四个规则,我们称它们为“key”、“value”、“pair”和“query”。实际上“value”应该看起来像(“query”|“unquotedvalue”),它创建了一种嵌套的“query”。我使用“未引用”而不是“未转义”来避免 url 转义混淆
-
很抱歉,我很难理解您想问的问题。我建议它可能是具有预期输出的 SCCEE。最好更简单。
-
sehe,是的,我知道,重新阅读我的问题我意识到我很难清楚地定义问题,并且问题中充满了技术细节,这(可能)不太重要,我会尝试再次定义问题
标签: c++ boost boost-spirit boost-spirit-qi