Кто-нибудь знает какой-нибудь хороший код на C ++, который делает это?
c++
urlencode
urldecode
percent-encoding
user126593
источник
источник
Ответы:
Я на днях столкнулся с половиной этой проблемы с кодировкой. Недовольный доступными параметрами, взглянув на этот пример кода C , я решил использовать свою собственную функцию кодирования URL-адресов C ++:
#include <cctype> #include <iomanip> #include <sstream> #include <string> using namespace std; string url_encode(const string &value) { ostringstream escaped; escaped.fill('0'); escaped << hex; for (string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) { string::value_type c = (*i); // Keep alphanumeric and other accepted characters intact if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { escaped << c; continue; } // Any other characters are percent-encoded escaped << uppercase; escaped << '%' << setw(2) << int((unsigned char) c); escaped << nouppercase; } return escaped.str(); }
Реализация функции декодирования предоставляется читателю в качестве упражнения. :П
источник
setw(0)
вызов (в то время я думал, что минимальная ширина останется установленной, пока я не верну ее обратно, но на самом деле она сбрасывается после следующего ввода).isalnum(c)
его нужно изменить наisalnum((unsigned char) c)
Отвечая на свой вопрос ...
libcurl имеет curl_easy_escape для кодирования.
Для декодирования curl_easy_unescape
источник
string urlDecode(string &SRC) { string ret; char ch; int i, ii; for (i=0; i<SRC.length(); i++) { if (int(SRC[i])==37) { sscanf(SRC.substr(i+1,2).c_str(), "%x", &ii); ch=static_cast<char>(ii); ret+=ch; i=i+2; } else { ret+=SRC[i]; } } return (ret); }
не лучший, но работает нормально ;-)
источник
'%'
вместо37
.cpp-netlib имеет функции
namespace boost { namespace network { namespace uri { inline std::string decoded(const std::string &input); inline std::string encoded(const std::string &input); } } }
они позволяют очень легко кодировать и декодировать строки URL.
источник
Обычно добавление "%" к значению int символа не работает при кодировании, значение предполагается в шестнадцатеричном эквиваленте. например, «/» - это «% 2F», а не «% 47».
Я думаю, что это лучшие и краткие решения как для кодирования, так и для декодирования URL-адресов (без особых зависимостей заголовков).
string urlEncode(string str){ string new_str = ""; char c; int ic; const char* chars = str.c_str(); char bufHex[10]; int len = strlen(chars); for(int i=0;i<len;i++){ c = chars[i]; ic = c; // uncomment this if you want to encode spaces with + /*if (c==' ') new_str += '+'; else */if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') new_str += c; else { sprintf(bufHex,"%X",c); if(ic < 16) new_str += "%0"; else new_str += "%"; new_str += bufHex; } } return new_str; } string urlDecode(string str){ string ret; char ch; int i, ii, len = str.length(); for (i=0; i < len; i++){ if(str[i] != '%'){ if(str[i] == '+') ret += ' '; else ret += str[i]; }else{ sscanf(str.substr(i + 1, 2).c_str(), "%x", &ii); ch = static_cast<char>(ii); ret += ch; i = i + 2; } } return ret; }
источник
if(ic < 16) new_str += "%0";
Для чего это питание ?? @tormuto @reliasn[Режим некроманта
включен ] Наткнулся на этот вопрос, когда искал быстрое, современное, платформо-независимое и элегантное решение. Мне не понравилось что-либо из вышеперечисленного, cpp-netlib будет победителем, но он имеет ужасающую уязвимость памяти в функции "декодирования". Так что я придумал решение для духовной ци / кармы boost.
namespace bsq = boost::spirit::qi; namespace bk = boost::spirit::karma; bsq::int_parser<unsigned char, 16, 2, 2> hex_byte; template <typename InputIterator> struct unescaped_string : bsq::grammar<InputIterator, std::string(char const *)> { unescaped_string() : unescaped_string::base_type(unesc_str) { unesc_char.add("+", ' '); unesc_str = *(unesc_char | "%" >> hex_byte | bsq::char_); } bsq::rule<InputIterator, std::string(char const *)> unesc_str; bsq::symbols<char const, char const> unesc_char; }; template <typename OutputIterator> struct escaped_string : bk::grammar<OutputIterator, std::string(char const *)> { escaped_string() : escaped_string::base_type(esc_str) { esc_str = *(bk::char_("a-zA-Z0-9_.~-") | "%" << bk::right_align(2,0)[bk::hex]); } bk::rule<OutputIterator, std::string(char const *)> esc_str; };
Использование вышеуказанного как следующее:
std::string unescape(const std::string &input) { std::string retVal; retVal.reserve(input.size()); typedef std::string::const_iterator iterator_type; char const *start = ""; iterator_type beg = input.begin(); iterator_type end = input.end(); unescaped_string<iterator_type> p; if (!bsq::parse(beg, end, p(start), retVal)) retVal = input; return retVal; } std::string escape(const std::string &input) { typedef std::back_insert_iterator<std::string> sink_type; std::string retVal; retVal.reserve(input.size() * 3); sink_type sink(retVal); char const *start = ""; escaped_string<sink_type> g; if (!bk::generate(sink, g(start), input)) retVal = input; return retVal; }
[Режим некроманта отключен]
EDIT01: исправлено заполнение нулями - особая благодарность
Хартмуту Кайзеру EDIT02: Live on CoLiRu
источник
cpp-netlib
? Вы можете дать краткое объяснение или ссылку?CGICC включает в себя методы кодирования и декодирования URL. form_urlencode и form_urldecode
источник
Вдохновленный xperroni, я написал декодер. Спасибо за указатель.
#include <iostream> #include <sstream> #include <string> using namespace std; char from_hex(char ch) { return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10; } string url_decode(string text) { char h; ostringstream escaped; escaped.fill('0'); for (auto i = text.begin(), n = text.end(); i != n; ++i) { string::value_type c = (*i); if (c == '%') { if (i[1] && i[2]) { h = from_hex(i[1]) << 4 | from_hex(i[2]); escaped << h; i += 2; } } else if (c == '+') { escaped << ' '; } else { escaped << c; } } return escaped.str(); } int main(int argc, char** argv) { string msg = "J%C3%B8rn!"; cout << msg << endl; string decodemsg = url_decode(msg); cout << decodemsg << endl; return 0; }
edit: удалены ненужные cctype и iomainip.
источник
Добавление дополнения к рекомендации Билла по использованию libcurl: отличное предложение и будет обновлено:
через 3 года функция curl_escape устарела, поэтому для будущего использования лучше использовать curl_easy_escape .
источник
Я столкнулся с этим вопросом при поиске api для декодирования URL-адреса в приложении win32 c ++. Поскольку вопрос не совсем определяет платформу, предполагается, что окна - это не плохо.
InternetCanonicalizeUrl - это API для программ Windows. Больше информации здесь
LPTSTR lpOutputBuffer = new TCHAR[1]; DWORD dwSize = 1; BOOL fRes = ::InternetCanonicalizeUrl(strUrl, lpOutputBuffer, &dwSize, ICU_DECODE | ICU_NO_ENCODE); DWORD dwError = ::GetLastError(); if (!fRes && dwError == ERROR_INSUFFICIENT_BUFFER) { delete lpOutputBuffer; lpOutputBuffer = new TCHAR[dwSize]; fRes = ::InternetCanonicalizeUrl(strUrl, lpOutputBuffer, &dwSize, ICU_DECODE | ICU_NO_ENCODE); if (fRes) { //lpOutputBuffer has decoded url } else { //failed to decode } if (lpOutputBuffer !=NULL) { delete [] lpOutputBuffer; lpOutputBuffer = NULL; } } else { //some other error OR the input string url is just 1 char and was successfully decoded }
InternetCrackUrl ( здесь ) также, похоже, имеет флаги, чтобы указать, нужно ли декодировать URL
источник
Я не смог найти здесь URI decode / unescape, который также декодирует 2- и 3-байтовые последовательности. Внесу свой вклад в мою собственную высокопроизводительную версию, которая на лету преобразует ввод c sting в wstring:
#include <string> const char HEX2DEC[55] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1, -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,10,11,12, 13,14,15 }; #define __x2d__(s) HEX2DEC[*(s)-48] #define __x2d2__(s) __x2d__(s) << 4 | __x2d__(s+1) std::wstring decodeURI(const char * s) { unsigned char b; std::wstring ws; while (*s) { if (*s == '%') if ((b = __x2d2__(s + 1)) >= 0x80) { if (b >= 0xE0) { // three byte codepoint ws += ((b & 0b00001111) << 12) | ((__x2d2__(s + 4) & 0b00111111) << 6) | (__x2d2__(s + 7) & 0b00111111); s += 9; } else { // two byte codepoint ws += (__x2d2__(s + 4) & 0b00111111) | (b & 0b00000011) << 6; s += 6; } } else { // one byte codepoints ws += b; s += 3; } else { // no % ws += *s; s++; } } return ws; }
источник
#define __x2d2__(s) (__x2d__(s) << 4 | __x2d__(s+1))
и он будет построен с -WError.wstring
нереально. По крайней мере,reserve
достаточно места, иначе у вас все время будут массовые перераспределения,В Windows API есть функции UrlEscape / UrlUnescape , экспортируемые shlwapi.dll для этой задачи.
источник
+
Эта версия - чистый C и может дополнительно нормализовать путь к ресурсам. Использование его с C ++ тривиально:
#include <string> #include <iostream> int main(int argc, char** argv) { const std::string src("/some.url/foo/../bar/%2e/"); std::cout << "src=\"" << src << "\"" << std::endl; // either do it the C++ conformant way: char* dst_buf = new char[src.size() + 1]; urldecode(dst_buf, src.c_str(), 1); std::string dst1(dst_buf); delete[] dst_buf; std::cout << "dst1=\"" << dst1 << "\"" << std::endl; // or in-place with the &[0] trick to skip the new/delete std::string dst2; dst2.resize(src.size() + 1); dst2.resize(urldecode(&dst2[0], src.c_str(), 1)); std::cout << "dst2=\"" << dst2 << "\"" << std::endl; }
Выходы:
src="/some.url/foo/../bar/%2e/" dst1="/some.url/bar/" dst2="/some.url/bar/"
И собственно функция:
#include <stddef.h> #include <ctype.h> /** * decode a percent-encoded C string with optional path normalization * * The buffer pointed to by @dst must be at least strlen(@src) bytes. * Decoding stops at the first character from @src that decodes to null. * Path normalization will remove redundant slashes and slash+dot sequences, * as well as removing path components when slash+dot+dot is found. It will * keep the root slash (if one was present) and will stop normalization * at the first questionmark found (so query parameters won't be normalized). * * @param dst destination buffer * @param src source buffer * @param normalize perform path normalization if nonzero * @return number of valid characters in @dst * @author Johan Lindh <johan@linkdata.se> * @legalese BSD licensed (http://opensource.org/licenses/BSD-2-Clause) */ ptrdiff_t urldecode(char* dst, const char* src, int normalize) { char* org_dst = dst; int slash_dot_dot = 0; char ch, a, b; do { ch = *src++; if (ch == '%' && isxdigit(a = src[0]) && isxdigit(b = src[1])) { if (a < 'A') a -= '0'; else if(a < 'a') a -= 'A' - 10; else a -= 'a' - 10; if (b < 'A') b -= '0'; else if(b < 'a') b -= 'A' - 10; else b -= 'a' - 10; ch = 16 * a + b; src += 2; } if (normalize) { switch (ch) { case '/': if (slash_dot_dot < 3) { /* compress consecutive slashes and remove slash-dot */ dst -= slash_dot_dot; slash_dot_dot = 1; break; } /* fall-through */ case '?': /* at start of query, stop normalizing */ if (ch == '?') normalize = 0; /* fall-through */ case '\0': if (slash_dot_dot > 1) { /* remove trailing slash-dot-(dot) */ dst -= slash_dot_dot; /* remove parent directory if it was two dots */ if (slash_dot_dot == 3) while (dst > org_dst && *--dst != '/') /* empty body */; slash_dot_dot = (ch == '/') ? 1 : 0; /* keep the root slash if any */ if (!slash_dot_dot && dst == org_dst && *dst == '/') ++dst; } break; case '.': if (slash_dot_dot == 1 || slash_dot_dot == 2) { ++slash_dot_dot; break; } /* fall-through */ default: slash_dot_dot = 0; } } *dst++ = ch; } while(ch); return (dst - org_dst) - 1; }
источник
сочные кусочки
#include <ctype.h> // isdigit, tolower from_hex(char ch) { return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10; } char to_hex(char code) { static char hex[] = "0123456789abcdef"; return hex[code & 15]; }
отмечая, что
char d = from_hex(hex[0]) << 4 | from_hex(hex[1]);
как в
// %7B = '{' char d = from_hex('7') << 4 | from_hex('B');
источник
Вы можете использовать функцию g_uri_escape_string (), предоставленную glib.h. https://developer.gnome.org/glib/stable/glib-URI-Functions.html
#include <stdio.h> #include <stdlib.h> #include <glib.h> int main() { char *uri = "http://www.example.com?hello world"; char *encoded_uri = NULL; //as per wiki (https://en.wikipedia.org/wiki/Percent-encoding) char *escape_char_str = "!*'();:@&=+$,/?#[]"; encoded_uri = g_uri_escape_string(uri, escape_char_str, TRUE); printf("[%s]\n", encoded_uri); free(encoded_uri); return 0; }
скомпилируйте его с помощью:
gcc encoding_URI.c `pkg-config --cflags --libs glib-2.0`
источник
Другое решение доступно с использованием библиотеки глупостей Facebook :
folly::uriEscape
иfolly::uriUnescape
.источник
Я знаю, что вопрос касается метода C ++, но для тех, кому он может понадобиться, я придумал очень короткую функцию на простом C для кодирования строки. Он не создает новую строку, а скорее изменяет существующую, что означает, что он должен иметь достаточный размер для размещения новой строки. Очень легко угнаться.
void urlEncode(char *string) { char charToEncode; int posToEncode; while (((posToEncode=strspn(string,"1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.~"))!=0) &&(posToEncode<strlen(string))) { charToEncode=string[posToEncode]; memmove(string+posToEncode+3,string+posToEncode+1,strlen(string+posToEncode)); string[posToEncode]='%'; string[posToEncode+1]="0123456789ABCDEF"[charToEncode>>4]; string[posToEncode+2]="0123456789ABCDEF"[charToEncode&0xf]; string+=posToEncode+3; } }
источник
вы можете просто использовать функцию AtlEscapeUrl () из atlutil.h, просто просмотрите ее документацию о том, как ее использовать.
источник
Пришлось сделать это в проекте без Boost. Итак, в итоге я написал свой. Я просто выложу его на GitHub: https://github.com/corporateshark/LUrlParser
clParseURL URL = clParseURL::ParseURL( "https://name:pwd@github.com:80/path/res" ); if ( URL.IsValid() ) { cout << "Scheme : " << URL.m_Scheme << endl; cout << "Host : " << URL.m_Host << endl; cout << "Port : " << URL.m_Port << endl; cout << "Path : " << URL.m_Path << endl; cout << "Query : " << URL.m_Query << endl; cout << "Fragment : " << URL.m_Fragment << endl; cout << "User name : " << URL.m_UserName << endl; cout << "Password : " << URL.m_Password << endl; }
источник