如何在C ++中解码带有UTF-8字符的URI

时间:2014-01-19 11:45:51

标签: c++ libcurl urldecode

我需要在C ++中解码URI。我发现了几个关于它的问题,但它们都没有处理UTF-8编码和重音(我对准确处理ASCII字符感兴趣)。

然后,我使用了像libcurl这样广泛使用的库...但它也未能解决UTF-8编码问题。这就是我正在做的事情

string UriHelper::Decode(const string &encoded)
{
    CURL *curl = curl_easy_init();
    int outlength;
    char *cres = curl_easy_unescape(curl, encoded.c_str(), encoded.length(), &outlength);
    string res(cres, cres + outlength);
    curl_free(cres);
    curl_easy_cleanup(curl);
    return res;
}

问题在于,a%C3%A1e%C3%A9i%C3%ADo%C3%B3u%C3%BAaáeéiíoóuú时应被aáeéiíoóuú解码为a%E1e%E9i%EDo%F3u%FA。如果我使用{{1}}它就可以了。

是否有任何库可以处理不同编码的URI并处理它们?

谢谢!

2 个答案:

答案 0 :(得分:2)

您的解码没有任何问题。打印解码的URL是个问题。您打印到的输出设备配置为接受以ISO-8859-1编码的字符串,而不是UTF-8。

将输出设备配置为接受以UTF-8编码的字符串或将解码后的URL从UTF-8转换为ISO-8859-1。

答案 1 :(得分:1)

正如Oswald所说,问题不在于解码......而在于我用于显示字符串的方法。因为我不需要处理UTF-8字符串,所以我将继续他的第二个建议并将其转换为ISO-8859-1。

从这个答案Is there a way to convert from UTF8 to iso-8859-1?

中借用了这个想法(以及大部分代码)

为了做到这一点,我在iconv中添加了依赖。

这是我的 UriHelper.h

#pragma once

using namespace std;

static class UriHelper
{
public:
    static string Encode(const string &source);
    static string Decode(const string &encoded);
};

这是我的 UriHelper.cpp

#include "UriHelper.h"
#include <curl/curl.h>
#include <iconv.h>

string UriHelper::Encode(const string &source)
{
    CURL *curl = curl_easy_init();
    char *cres = curl_easy_escape(curl, source.c_str(), source.length());
    string res(cres);
    curl_free(cres);
    curl_easy_cleanup(curl);
    return res;
}

string UriHelper::Decode(const string &encoded)
{
    CURL *curl = curl_easy_init();
    int outlength;
    char *cres = curl_easy_unescape(curl, encoded.c_str(), encoded.length(), &outlength);
    string res(cres, cres + outlength);
    curl_free(cres);
    curl_easy_cleanup(curl);

    //if it's UTF-8, convert it to ISO_8859-1. Based on https://stackoverflow.com/questions/11156473/is-there-a-way-to-convert-from-utf8-to-iso-8859-1/11156490#11156490
    iconv_t cd = iconv_open("ISO_8859-1", "UTF-8");

    const char *in_buf = res.c_str();
    size_t in_left = res.length();

    char *output = new char[res.length() + 1];
    std::fill(output, output + res.length() + 1, '\0');
    char *out_buf = &output[0];
    size_t out_left = res.length();

    do {
        if (iconv(cd, &in_buf, &in_left, &out_buf, &out_left) == (size_t)-1) {
            //failed to convert, just return the value received from curl
            delete[] output;
            iconv_close(cd);
            return res;
        }
    } while (in_left > 0 && out_left > 0);

    string outputString(output);
    delete[] output;
    iconv_close(cd);

    return outputString;
}