Не экранируйте URL-адрес весь как одну строку. Избегайте только отдельных частей, которые на самом деле нужно экранировать, например параметров запроса. Но даже тогда, в парах name=value
, экранируйте name
и value
отдельно при необходимости, в противном случае разделитель =
в паре name=value
и разделитель &
между парами будут экранированы, что ты не хочешь случиться.
Попробуйте что-то еще подобное:
std::string query_encode(const std::string &s)
{
std::string ret;
// curl_easy_escape() escapes way more than it needs to in
// a URL Query component! Which is not TECHNICALLY wrong, but
// it won't produce the output you are expecting...
/*
char *output = curl_easy_escape(curl, s.c_str(), s.length());
if (output) {
ret = output;
curl_free(output);
}
*/
#define IS_BETWEEN(ch, low, high) (ch >= low && ch <= high)
#define IS_ALPHA(ch) (IS_BETWEEN(ch, 'A', 'Z') || IS_BETWEEN(ch, 'a', 'z'))
#define IS_DIGIT(ch) IS_BETWEEN(ch, '0', '9')
#define IS_HEXDIG(ch) (IS_DIGIT(ch) || IS_BETWEEN(ch, 'A', 'F') || IS_BETWEEN(ch, 'a', 'f'))
for(size_t i = 0; i < s.size();)
{
char ch = s[i++];
if (IS_ALPHA(ch) || IS_DIGIT(ch))
{
ret += ch;
}
else if ((ch == '%') && IS_HEXDIG(s[i+0]) && IS_HEXDIG(s[i+1]))
{
ret += s.substr(i-1, 3);
i += 2;
}
else
{
switch (ch)
{
case '-':
case '.':
case '_':
case '~':
case '!':
case '$':
case '&':
case '\'':
case '(':
case ')':
case '*':
case '+':
case ',':
case ';':
case '=':
case ':':
case '@':
case '/':
case '?':
case '[':
case ']':
ret += ch;
break;
default:
{
static const char hex[] = "0123456789ABCDEF";
char pct[] = "% ";
pct[1] = hex[(ch >> 4) & 0xF];
pct[2] = hex[ch & 0xF];
ret.append(pct, 3);
break;
}
}
}
}
return ret;
}
std::string d = "https://www.overpass-api.de/api/interpreter?data=" + query_encode("area[\"name\"=\"Nicaragua\"][\"admin_level\"=\"2\"]->.boundaryarea;(node[\"type\"=\"route\"][\"route\"=\"bus\"](area.boundaryarea);way[\"type\"=\"route\"][\"route\"=\"bus\"](area.boundaryarea);>;relation[\"type\"=\"route\"][\"route\"=\"bus\"](area.boundaryarea);>>;);out meta;");
std::cout << "Encoded: " + d + "\n";
Демоверсия
Выход:
https://www.overpass-api.de/api/interpreter?data=area[%22name%22=%22Nicaragua%22][%22admin_level%22=%222%22]-%3E.boundaryarea;(node[%22type%22=%22route%22][%22route%22=%22bus%22](area.boundaryarea);way[%22type%22=%22route%22][%22route%22=%22bus%22](area.boundaryarea);%3E;relation[%22type%22=%22route%22][%22route%22=%22bus%22](area.boundaryarea);%3E%3E;);out%20meta;
Почему некоторые символы кодируются, а не остальные?
Правила охватываются RFC 3986 , в частности Разделом 2 «Символы» и его подразделами 2.1 - 2.5. Компонент Query охватывается Разделом 3.4 .