Я пытаюсь разобрать строку запроса URL со специальными правилами. До сих пор он работает с одним исключение описано ниже URL обрабатывается как набор пар ключ-значение, используя следующие:Разбор строки с дополнительным разделителем с использованием boost spirit
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 который должен разобрать на
- а => B
- д => х
- е => г = ч & I = J
- х => у
- х => Защита
Так я добавил дополнительное правило для «цитировал» значение
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);
, который в очередной раз работал не ожидается до следующего случая - а = Ь & d = е & е = $$ г = h & i = j $$ x = y & z = def, note, нет амперсанда между закрытием «$$» и следующим именем ключа. похоже, его легко решить, добавив оператора 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;
}
Выход для "а = Ь & г = е = & е $$ г = & ч I = J $$ х = у = & г DEF" (ошибочное , должны быть такими же, как и для "A = B = & д е & е = $$ г = & ч I = J $$ & х = у = & г DEF")
("а", "b"), ("d", "e "), (" Ф " "г = & ч г = JX")
Выход для" а = Ь & г = е = & е $$ г = & ч I = J $$ & х = у & г = DEF "(как ожидалось)
("а", "б"), ("д", "е"), ("F"," G = H & I = J "), (" х», "у"), ("г", "DEF")
EDIT: Несколько простых правил разбора, просто сделать материал легче понять
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] (http://coliru.stacked-crooked.com/a/9702b2ebd5e6535f). Я не уверен, что понимаю ваше намерение, ваша ожидаемая карта 'map = {{a, b}, {d, e}, {f, g = h & i = j}, {x, y}, {z, def }}; '? – llonesmiz
Правило 'value' должно быть' escapedValue | "unescapedValue" ', правильно? Потому что то, что у вас сейчас, отличается. – llonesmiz
Нет, ситуация несколько сложнее, есть четыре правила, позволяет называть em «ключ», «значение», «пара» и «запрос». Фактически «значение» должно выглядеть так («query» | «unquotedvalue»), он создает своего рода вложенный «запрос». Я использую «unquoted» вместо «unescaped», чтобы избежать ошибки при запуске. – kreuzerkrieg