เข้ารหัส / ถอดรหัส URL ใน C ++ [ปิด]


85

ไม่มีใครรู้รหัส C ++ ที่ดีที่ทำสิ่งนี้?


3
แล้วจะยอมรับคำตอบได้อย่างไร?
gsamaras

คำตอบ:


83

ฉันประสบปัญหาครึ่งหนึ่งของการเข้ารหัสเมื่อวันก่อน ไม่พอใจกับตัวเลือกที่มีอยู่และหลังจากดูโค้ดตัวอย่าง 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();
}

การใช้งานฟังก์ชั่นถอดรหัสถูกปล่อยให้เป็นแบบฝึกหัดสำหรับผู้อ่าน : ป


1
ฉันเชื่อว่าการแทนที่ '' ด้วย "% 20" เป็นเรื่องทั่วไปมากกว่า ฉันได้อัปเดตรหัสตามนั้น อย่าลังเลที่จะย้อนกลับหากคุณไม่เห็นด้วย
Josh Kelley

1
ไม่ฉันเห็นด้วย ยังมีโอกาสลบการsetw(0)โทรที่ไม่มีจุดหมายนั้นออก (ในขณะนั้นฉันคิดว่าความกว้างน้อยที่สุดจะยังคงตั้งค่าได้จนกว่าฉันจะเปลี่ยนกลับ แต่ในความเป็นจริงมันจะถูกรีเซ็ตหลังจากอินพุตถัดไป)
xperroni

1
ฉันต้องเพิ่ม std :: ตัวพิมพ์ใหญ่ในบรรทัด "Escape << '%' << std :: uppercase << std :: setw (2) << int ((ไม่ได้ลงนามถ่าน) c);" ในกรณีที่คนอื่นสงสัยว่าเหตุใดจึงส่งคืนตัวอย่างเช่น% 3a แทนที่จะเป็น% 3A
gumlym

2
ดูเหมือนไม่ถูกต้องเนื่องจากไม่รองรับสตริง UTF-8 ( w3schools.com/tags/ref_urlencode.asp ) ดูเหมือนว่าจะใช้ได้เฉพาะกับ Windows-1252
Skywalker13

1
ปัญหาก็แค่isalnum(c)ต้องเปลี่ยนเป็นisalnum((unsigned char) c)
Skywalker13

76

กำลังตอบคำถามของตัวเอง ...

libcurl มีcurl_easy_escapeสำหรับการเข้ารหัส

สำหรับการถอดรหัสcurl_easy_unescape


4
คุณควรยอมรับคำตอบนี้เพื่อแสดงไว้ที่ด้านบนสุด (และผู้คนจะค้นพบได้ง่ายขึ้น)
Mouagip

คุณต้องใช้ curl เพื่อให้ได้ผลและต้องเพิ่มหน่วยความจำ
xinthose

คำถามที่เกี่ยวข้อง: ทำไม unescape ของ curl ถึงไม่จัดการกับการเปลี่ยน '+' เป็น space? นั่นไม่ใช่ขั้นตอนมาตรฐานเมื่อถอดรหัส URL ใช่หรือไม่
Stéphane

12
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);
}

ไม่ดีที่สุด แต่ทำงานได้ดี ;-)


5
แน่นอนคุณควรใช้'%'แทน37.
John Zwinck

4
สิ่งนี้ไม่ได้แปลง '+' เป็นช่องว่าง
xryl669

11

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 ได้ง่ายมาก


2
ขอบคุณครับ เอกสารประกอบเกี่ยวกับ cpp-netlib นั้นเบาบาง คุณมีลิงค์ไปยังเอกสารโกงดีๆหรือไม่?
user249806

8

โดยปกติการเพิ่ม '%' ให้กับค่า 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
KriyenKP

1
@Kriyen ใช้เพื่อเติม HEX ที่เข้ารหัสด้วยศูนย์นำหน้าในกรณีที่ผลลัพธ์เป็นตัวอักษรตัวเดียว ตั้งแต่ 0 ถึง 15 ใน HEX คือ 0 ถึง F
tormuto

1
ฉันชอบแนวทางนี้ที่สุด +1 สำหรับการใช้ไลบรารีมาตรฐาน แม้ว่าจะมีสองปัญหาที่ต้องแก้ไข ฉันเป็นคนเช็กและใช้อักษร "ý" ผลลัพธ์คือ "% 0FFFFFFC3% 0FFFFFFBD" การใช้สวิตช์ 16 ครั้งแรกไม่จำเป็นเนื่องจากการรับประกัน utf8 เพื่อเริ่มต้นไบต์ต่อท้ายทั้งหมดด้วย 10 และดูเหมือนว่าจะล้มเหลวหลายไบต์ของฉัน ประเด็นที่สองคือ FF เนื่องจากไม่ใช่คอมพิวเตอร์ทุกเครื่องที่มีจำนวนบิตต่อ int เท่ากัน การแก้ไขคือข้ามสวิตช์ 16 ตัว (ไม่จำเป็น) และคว้าสองตัวอักษรสุดท้ายจากบัฟเฟอร์ (ฉันใช้สตริงสตรีมเนื่องจากฉันรู้สึกสบายใจมากขึ้นและบัฟเฟอร์สตริง) ยังคงให้จุด ชอบเฟรมด้วย
Volt

@ Volt คุณสามารถโพสต์รหัสที่อัปเดตในคำตอบใหม่ได้หรือไม่? คุณพูดถึงปัญหา แต่ข้อมูลไม่เพียงพอสำหรับการแก้ไขที่ชัดเจน
gregn3

คำตอบนี้มีปัญหาเนื่องจากใช้ strlen ประการแรกนี่ไม่สมเหตุสมผลเพราะเรารู้ขนาดของสตริงออบเจ็กต์อยู่แล้วจึงเสียเวลา ที่แย่กว่านั้นคือสตริงอาจมี 0 ไบต์ซึ่งอาจสูญหายไปเพราะ strlen นอกจากนี้ if (i <16) ก็ไม่มีประสิทธิภาพเนื่องจาก printf สามารถครอบคลุมได้เองโดยใช้ "%%% 02X" และสุดท้าย c ควรเป็นไบต์ที่ไม่ได้ลงนามมิฉะนั้นคุณจะได้รับเอฟเฟกต์ที่ @Volt อธิบายโดยนำหน้า '0xFFF ... '
Devolus

8

[โหมด Necromancer เปิด]
สะดุดกับคำถามนี้เมื่อกำลังมองหาโซลูชันที่รวดเร็วทันสมัยเป็นอิสระและสง่างาม cpp-netlib ไม่เหมือนกับข้อใดข้างต้น แต่ก็มีช่องโหว่ของหน่วยความจำที่น่ากลัวในฟังก์ชัน "ถอดรหัส" ดังนั้นฉันจึงหาวิธีแก้ปัญหาจิตวิญญาณ / กรรมของบูสต์

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;
}

[โหมด Necromancer ปิด]

แก้ไข 01: แก้ไขสิ่งที่เป็นศูนย์ - ขอขอบคุณเป็นพิเศษสำหรับ Hartmut Kaiser
EDIT02: Live บน CoLiRu


“ ช่องโหว่ของหน่วยความจำที่น่ากลัว” cpp-netlibคืออะไร? คุณสามารถให้คำอธิบายสั้น ๆ หรือลิงค์ได้หรือไม่?
Craig M. Brandenburg

มีการรายงาน (ปัญหา) แล้วดังนั้นฉันจึงไม่ได้รายงานและจำไม่ได้จริงๆ ... บางอย่างเช่นการละเมิดการเข้าถึงเมื่อพยายามแยกวิเคราะห์ลำดับการหลบหนีที่ไม่ถูกต้องหรือบางสิ่ง
kreuzerkrieg

โอ้นี่คุณไปที่github.com/cpp-netlib/cpp-netlib/issues/501
kreuzerkrieg

ขอบคุณที่ชี้แจง!
Craig M. Brandenburg


6

แรงบันดาลใจจาก 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;
}

แก้ไข: ลบ cctype ที่ไม่จำเป็นและ iomainip รวมอยู่ด้วย


1
บล็อก "if (c == '%')" ต้องการการตรวจสอบนอกขอบเขตมากขึ้น i [1] และ / หรือ i [2] อาจอยู่เกิน text.end () ฉันจะเปลี่ยนชื่อ "Escape" เป็น "Unescaped" ด้วย "Escape.fill ('0');" อาจไม่จำเป็น
roalz

โปรดดูเวอร์ชันของฉัน มีการปรับให้เหมาะสมมากขึ้น pastebin.com/g0zMLpsj
KoD

4

เพิ่มการติดตามคำแนะนำของบิลสำหรับการใช้ libcurl: ข้อเสนอแนะที่ดีและได้รับการปรับปรุง:
หลังจาก 3 ปีที่ผ่านมาcurl_escapeฟังก์ชั่นจะเลิกเพื่อสำหรับใช้ในอนาคตมันจะดีกว่าที่จะใช้curl_easy_escape


4

ฉันจบลงด้วยคำถามนี้เมื่อค้นหา api เพื่อถอดรหัส url ในแอป win32 c ++ เนื่องจากคำถามไม่ได้ระบุแพลตฟอร์มมากนักโดยถือว่า windows ไม่ใช่เรื่องเลวร้าย

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 หรือไม่


3

ฉันไม่พบการถอดรหัส URI / unescape ที่นี่ซึ่งถอดรหัสลำดับ 2 และ 3 ไบต์ด้วย การมีส่วนร่วมในเวอร์ชันประสิทธิภาพสูงของฉันเองที่ on-the-fly จะแปลงอินพุต c ต่อยเป็น 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
Janek Olszak

ขออภัย "ประสิทธิภาพสูง" ในขณะที่การเพิ่มตัวอักษรเดี่ยวลงใน a wstringนั้นไม่สมจริง อย่างน้อยก็reserveมีพื้นที่เพียงพอมิฉะนั้นคุณจะมีการจัดสรรจำนวนมากตลอดเวลา
Felix Dombek


1

เวอร์ชันนี้เป็น 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;
}

ขอบคุณ. นี่คือสิ่งที่ไม่มีเส้นทางเสริม pastebin.com/RN5g7g9u
Julian

สิ่งนี้ไม่เป็นไปตามคำแนะนำใด ๆ และผิดอย่างสิ้นเชิงเมื่อเทียบกับสิ่งที่ผู้เขียนขอ (เช่น '+' จะไม่ถูกแทนที่ด้วยช่องว่าง) การทำให้เป็นมาตรฐานของเส้นทางไม่มีส่วนเกี่ยวข้องกับการถอดรหัส URL หากคุณตั้งใจจะทำให้เส้นทางของคุณเป็นปกติคุณควรแยก URL ของคุณออกเป็นส่วน ๆ ก่อน (โครงร่างอำนาจเส้นทางแบบสอบถามส่วนย่อย) จากนั้นใช้อัลกอริทึมที่คุณต้องการเฉพาะในส่วนของเส้นทางเท่านั้น
xryl669

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');

1

คุณสามารถใช้ฟังก์ชัน "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`


0

ฉันรู้ว่าคำถามถามถึงวิธีการ 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;
    }
}

0

คุณสามารถใช้ฟังก์ชัน AtlEscapeUrl () จาก atlutil.h เพียงอ่านเอกสารเกี่ยวกับวิธีการใช้งาน


1
สิ่งนี้ใช้ได้กับ windows เท่านั้น
kritzikratzi

ใช่ฉันได้ลองสิ่งนี้บน windows
Pratik

-2

ต้องทำในโครงการที่ไม่มี 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;
}

ลิงก์ของคุณคือไลบรารีที่แยกวิเคราะห์ URL ไม่% - เข้ารหัส URL (หรืออย่างน้อยฉันก็มองไม่เห็น% ในแหล่งที่มา) ดังนั้นฉันจึงไม่คิดว่าสิ่งนี้จะตอบคำถาม
Martin Bonner สนับสนุน Monica
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.