在将某些字符处理到URL时遇到了很多麻烦,让我们假设我有以下网址:
http://localhost/somewere/myLibrary.dll/rest/something?parameter=An%C3%A1lisis
必须转换为:
http://localhost/somewere/myLibrary.dll/rest/something?parameter=Análisis
为了处理变音符号的解码,我决定使用InternetCanonicalizeUrl函数,因为我正在处理的应用程序只能在Windows中运行而我不想要要安装其他库,我使用的辅助函数如下:
String DecodeURL(const String &a_URL)
{
String result;
unsigned long size = a_reportType.Length() * 2;
wchar_t *buffer = new wchar_t[size];
if (InternetCanonicalizeUrlW(a_URL.c_str(), buffer, &size, ICU_DECODE | ICU_NO_ENCODE))
{
result = buffer;
}
delete [] buffer;
return result;
}
对于几乎所有通过它的URL都有效,除了变音符号外,我的示例URL解码如下:
http://localhost/somewere/myLibrary.dll/rest/something?parameter=Análisis
我正在使用的IDE是CodeGear™C ++Builder®2009(这就是为什么我强制使用String
代替std::string
),I我还尝试使用AnsiString
和char buffer
版本,但结果相同。
有关如何处理此错误的任何提示/替代方法?
提前致谢。
答案 0 :(得分:3)
InternetCanonicalizeUrl()
正在做正确的事情,你只需要考虑它实际上在做什么。
URL不支持Unicode(IRIs),因此必须将Unicode数据字符集编码为字节八位字节,然后根据需要使用%HH
序列对这些八位字节进行URL编码。在这种情况下,数据被编码为UTF-8(现在在许多URL中并不常见,但也不能保证),但是InternetCanonicalizeUrl()
无法知道因为URL没有描述哪个字符集的语法正在使用。它所能做的只是将%HH
序列解码为相关的字节八位字节值,它不能为您解码八位字节。对于Unicode版本,InternetCanonicalizeUrlW()
将这些字节值原样返回为wchar_t
个元素。但不管怎样,你必须自己对八位字节进行字符串解码才能恢复原始的Unicode数据。
因此,在这种情况下你可以做的是将解码后的数据复制到UTF8String
,然后将其作为String
分配/返回,以便将其解码为UTF-16。当然,这只适用于UTF-8编码的URL。例如:
String DecodeURL(const String &a_URL)
{
DWORD size = 0;
if (!InternetCanonicalizeUrlW(a_URL.c_str(), NULL, &size, ICU_DECODE | ICU_NO_ENCODE))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
String buffer;
buffer.SetLength(size-1);
if (InternetCanonicalizeUrlW(a_URL.c_str(), buffer.c_str(), &size, ICU_DECODE | ICU_NO_ENCODE))
{
UTF8String utf8;
utf8.SetLength(buffer.Length());
for (int i = 1; i <= buffer.Length(); ++i)
utf8[i] = (char) buffer[i];
return utf8;
}
}
}
return String();
}
可替换地:
// encoded URLs are always ASCII, so it is safe
// to pass an encoded URL UnicodeString as an
// AnsiString...
String DecodeURL(const AnsiString &a_URL)
{
DWORD size = 0;
if (!InternetCanonicalizeUrlA(a_URL.c_str(), NULL, &size, ICU_DECODE | ICU_NO_ENCODE))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
UTF8String buffer;
buffer.SetLength(size-1);
if (InternetCanonicalizeUrlA(a_URL.c_str(), buffer.c_str(), &size, ICU_DECODE | ICU_NO_ENCODE))
{
return utf8;
}
}
}
仅供参考,C ++ Builder预装了Indy。 Indy有一个TIdURI
类,可以解码URL并考虑字符集,例如:
#include <IdGlobal.hpp>
#include <IdURI.hpp>
String DecodeURL(const String &a_URL)
{
return TIdURI::URLDecode(URL, enUTF8);
}
在任何情况下,您都必须知道用于对URL数据进行编码的字符集。如果不这样做,您所能做的就是解码原始八位字节,然后使用启发式分析来猜测字符集可能是什么,但对于非ASCII和非UTF字符集,这不是100%可靠。