2014-01-23 2 views
0

Я пытаюсь разобрать строку запроса 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("&amp;")|'&') >> 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("&amp;")|'&') >> 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("&amp;")|'&') >> 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("&amp;")|'&') >> 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); 
} 
+0

Проще получить помощь, когда вы предоставляете компилируемый пример, например [this] (http://coliru.stacked-crooked.com/a/9702b2ebd5e6535f). Я не уверен, что понимаю ваше намерение, ваша ожидаемая карта 'map = {{a, b}, {d, e}, {f, g = h & i = j}, {x, y}, {z, def }}; '? – llonesmiz

+0

Правило 'value' должно быть' escapedValue | "unescapedValue" ', правильно? Потому что то, что у вас сейчас, отличается. – llonesmiz

+0

Нет, ситуация несколько сложнее, есть четыре правила, позволяет называть em «ключ», «значение», «пара» и «запрос». Фактически «значение» должно выглядеть так («query» | «unquotedvalue»), он создает своего рода вложенный «запрос». Я использую «unquoted» вместо «unescaped», чтобы избежать ошибки при запуске. – kreuzerkrieg

ответ

1

Я думаю, ваш проблемой является value правилу

value = *(escapedValue | (char_ - '&' - '=')); 

при разборе ... $$ г = Н & I = J $$ х = ...

$$g=h&i=j$$x= 
^---------^ 

анализирует отмеченную строку $$g=h&i=j$$ как escapedValue, тогда оператор kleene (*) позволяет второй части (char_ - '&' - '=')value правило разбора x

$$g=h&i=j$$x= 
     ^

и только в = правило останавливается.

Может быть что-то вроде это поможет:

value = escapedValue | *(char_ - '&' - '='); 
+0

не имеют доступа к коду прямо сейчас, но у меня есть ощущение, что мне нужно обновить escape-правило до чего-то вроде qi :: omit ["$$"] >> * (qi :: char_ - '$') >> qi :: omit ["$$"] >> * (пара); – kreuzerkrieg

+0

так, этот ответ не помог? Еще ищете? –

+0

с помощью моего друга, который достаточно глубок в духе форсирования, я нашел решение, однако, я предпочитаю не использовать его – kreuzerkrieg

0

это решает проблему. однако я решил отказаться от идеи использования духа для синтаксического анализа строки запроса - каждый особый случай делает запрос более громоздким, через некоторое время никто не запомнит, почему запрос написан так, как он есть :)

qi::rule<std::string::const_iterator, std::string()> key = +(qi::char_ - '=' - '&'); 
qi::rule<std::string::const_iterator, std::string()> escapedValue = qi::omit["$$"] >> *(qi::char_ - "$$") >> qi::omit["$$"]; 
qi::rule<std::string::const_iterator, std::string()> nonEscapedValue = !qi::lit("$$") >> *(qi::char_ - '=' - '&'); 

auto sep = qi::lit("&amp;") | '&'; 
qi::rule<std::string::const_iterator, std::pair<std::string, boost::optional<std::string>>()> keyValue = 
     key >> -('=' >> nonEscapedValue) >> (sep | qi::eoi); 
qi::rule<std::string::const_iterator, std::pair<std::string, boost::optional<std::string>>()> escapedKeyValue = 
     key >> '=' >> escapedValue >> -(sep); 
auto query = *(qi::hold[keyValue] | escapedKeyValue); 

 Смежные вопросы

  • Нет связанных вопросов^_^