2013-06-13 2 views
2

Я пытаюсь написать программу на C++, которая будет декодировать строку с кодировкой URL, содержащую URL-кодированные символы в Юникоде.UrlUnescape() и unicode chars

#include <windows.h> 
#include <string> 
#include <shlwapi.h> 
#pragma comment(lib, "Shlwapi.lib") 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    std::wstring test = L"bla+%D0%B1%D0%BB%D0%BE%D1%84+%E6%97%A5%E6%9C%AC%E8%AA%9E"; 
    PWSTR urlencodedStr = const_cast<WCHAR*>(test.c_str()); 
    WCHAR decodedStr[1025]; 
    DWORD size = 1024; 
    HRESULT hres = UrlUnescape(urlencodedStr, decodedStr, &size, NULL); 

    if (hres == S_OK) 
     MessageBox(NULL, decodedStr, L"decoded string", MB_OK); 

    return 0; 
} 

Я ожидаю, чтобы получить L "бла-блоф Расширенный" в decodedStr. Но вместо этого я получаю L "bla + Ð ± Ð" Ð¾Ñ "+ æ- ¥ 本語". Я использую кодировку unicode в моей сборке. Что я делаю неправильно?

ответ

1

Хорошо. Поэтому я написал свою собственную функцию для декодирования строк с кодировкой URL с символами Unicode. Вот оно:

#include <windows.h> 
#include <string> 
#include <shlwapi.h> 
#include <sstream> 
#include <iostream> 
#include <wininet.h> // For INTERNET_MAX_URL_LENGTH 

#pragma comment(lib, "Shlwapi.lib") 

bool IsHexChar(const WCHAR _char) 
{ 
    return ((_char == L'A') || 
      (_char == L'B') || 
      (_char == L'C') || 
      (_char == L'D') || 
      (_char == L'E') || 
      (_char == L'F') || 
      iswalnum(_char)); 
} 

std::wstring UrlDecode(const std::wstring& _encodedStr) 
{ 
    std::string charStr; 

    for (size_t i = 0; i < _encodedStr.length(); ++i) 
    { 
     if ((_encodedStr[i] == L'%') && (IsHexChar(_encodedStr[i+1])) && (IsHexChar(_encodedStr[i+2]))) 
     { 
      std::wstring hexCodeStr = L"0x"; 
      hexCodeStr += _encodedStr[i+1]; 
      hexCodeStr += _encodedStr[i+2]; 

      unsigned int hexCharCode; 
      std::wstringstream ss; 
      ss << std::hex << hexCodeStr; 
      ss >> hexCharCode; 

      charStr += static_cast<char>(hexCharCode); 

      i += 2; 
     } 
     else if (_encodedStr[i] == L'+') 
      charStr += L' '; 
     else 
      charStr += _encodedStr[i]; 
    } 

    WCHAR decodedStr[INTERNET_MAX_URL_LENGTH]; 
    MultiByteToWideChar(CP_UTF8, 0, charStr.c_str(), -1, decodedStr, sizeof(decodedStr)); 

    return decodedStr; 
} 

Использование так:

std::wstring encodedStr = L"bla+%D0%B1%D0%BB%D0%BE%D1%84+%E6%97%A5%E6%9C%AC%E8%AA%9E"; 
std::wstring decodedStr = UrlDecode(encodedStr); 
2

UrlUnescape конвертирует URL-декодированные %xx байты в символы, используя по умолчанию (ANSI) кодовую страницу. Это почти никогда не то, что вы хотите.

Начиная с Windows 8, вы можете передать флаг UNESCAPE_AS_UTF8, чтобы заставить его вести себя. Если вы не можете зависеть от Win8, вам придется использовать/написать другой вызов библиотеки декодирования URL-адресов, который не страдает от этой проблемы.

Также существует проблема +: в виде простого URL-кодирования (например, для использования в части пути) это означает плюс, но в форме-url-кодировании (например, в параметре запроса) , вот что вам кажется здесь, это означает пространство. Хороший декодер URL даст вам возможность сказать, какой из них вы имеете в виду; UrlUnescape нет. Альтернативой является замена вручную + места на входе перед расшифровкой URL; это один особый случай, и никакие другие персонажи не пострадали.