我正在尝试使用特殊规则解析 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 => def
所以我为“引用”值添加了额外的规则
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", "def")
编辑: 更简单的解析规则,只是为了让内容更容易理解
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);
}
最佳答案
我猜你的问题是 value
规则
value = *(escapedValue | (char_ - '&' - '='));
解析时...$$g=h&i=j$$x=...
$$g=h&i=j$$x=
^---------^
它将标记的字符串 $$g=h&i=j$$
解析为 escapedValue
,然后 kleene 运算符 (*) 允许第二部分 (char_ - '&' - '=')
的 value
规则解析 x
$$g=h&i=j$$x=
^
并且仅在 =
处规则停止。
也许这样的事情会有所帮助:
value = escapedValue | *(char_ - '&' - '=');
关于c++ - 使用 boost spirit 解析带有可选分隔符的字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21301777/