带中文的CString转URL(%XX)编码
不知道怎么的,百度搜 URL Encode 出来的结果就两种实现方法,都不能直接用,其中一种还要对 -125 进行专门的处理,而且出来的结果也有错误.另外搜到的一篇文章不是专门针对 CString 操作的,要转为对应的类型,再调用 4 5 个函数,很不舒服.查了一下标准,实际上也没啥特别的地方.所以自己写一个得了.
可以设置不编码字符,空格转码为 + 还是 %20 也不难弄.目前的主要做作用是要把所有字符编码打印出来一判断是否有编码错误,所以要小改一下才能对字符串进行编码,或者扩展哪部分需要编码.
// 最终代码:传入要编码的字符串(和不转换编码的字符),返回转换结果,不再写入到文件
// 对 CString URL 进行编码 // strNoEncode 为不编码的字符
static CString URLEncode(CString strToEncode, CString strNoEncode = L"")
{
// 默认不转换的字符
if (strNoEncode.IsEmpty())
{
strNoEncode = L"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:/.?_-=&";
}
CString strEncoded; // 转换结果
for (int i = 0; i < strToEncode.GetLength(); i++)
{
CString strCur = strToEncode.Mid(i, 1); // 当前要被转换的字符
// 判断是否需要转换
BOOL bNoEncode = FALSE;
for (int j = 0; j < strNoEncode.GetLength(); j++)
{
if (strCur == strNoEncode.Mid(j, 1))
{
bNoEncode = TRUE;
break;
}
}
// 不需要转换的字符直接拼接到要输出的字符串中
if (bNoEncode)
{
strEncoded += strCur;
continue;
}
// 需要转换的字符先转码
LPCWSTR unicode = T2CW(strCur);
int len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, 0, 0, 0, 0);
char *utf8 = new char[len];
WideCharToMultiByte(CP_UTF8, 0, unicode, len, utf8, len, 0, 0);
// 转码后的字符格式化拼接到输出的字符串中
for (int k = 0; k < len - 1; k++) // 不处理最后一个字符串终止符号
{
strEncoded.AppendFormat(L"%%%02X", utf8[k] & 0xFF);
}
}
return strEncoded;
}
// 测试代码:即时转换即时写入到文件,以利于遍历检查
CString URLEncode(CString strIn)//, char*cNoEncode)
{
// https://www.baidu.com/s?wd=url%E7%BC%96%E7%A0%81%E8%A7%84%E5%88%99&pn=20
// https://www.baidu.com/s?wd=url编码规则&pn=20
// 0-9,a-z,A-Z,/,:,?,=,&,.,
//if (IsDBCSLeadByte(utf8[i]) || utf8[i] == -128) // %80 // 并不完善
char cNoEncode[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:/.?=&";
// CString strSou = L"01AB文章春节 口语";
// int iMax = strSou.GetLength(); // 传入字符串时使用
int iMax = 1024 * 1024; // 目前用于测试转码是否有误
CString strEncode = L"";
CFile fLog;
if (fLog.Open(L"log2.log", CFile::modeCreate | CFile::modeWrite | CFile::shareDenyNone | CFile::typeUnicode))
{
//fLog.Write(strSou + L"\r\n", strSou.GetLength() * 2 + 4); // 测试时用于打印传入的字符串
for (int i = 0; i < iMax; i++)
{
// int iCur = *(strSou.GetBuffer() + i); // 传入字符串时使用
int iCur = i; // 获取当前字符
BOOL bNoEncode = FALSE;
for (int j = 0; j < strlen(cNoEncode); j++)
{
if (iCur == cNoEncode[j])
{
bNoEncode = TRUE;
break;
}
}
if (bNoEncode == TRUE) // 如果不需要转码
{
strEncode.Format(L"%c", iCur);
fLog.Write(strEncode, strEncode.GetLength() * 2);
continue;
}
else
{
// 为了打印出%00以扩展支持对文件编码,顺便把该范围的字符都处理了一下
if (iCur >= 0 && iCur <= 255)
{
strEncode.Format(L"%%%02X", iCur & 0xFF);
fLog.Write(strEncode, strEncode.GetLength() * 2);
continue;
}
// 对需要处理的字符进行转码(UNicode转ANSI)
// 目前以单个字符为单位,以避免字符过长对内存造成压力
CString strABC;
strABC.Format(L"%c", iCur);
LPCWSTR unicode = T2CW(strABC);
int len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, 0, 0, 0, 0);
char *utf8 = new char[len];
WideCharToMultiByte(CP_UTF8, 0, unicode, len, utf8, len, 0, 0);
// 目前测试到的中文一般len为3,
strEncode = L"";
for (int k = 0; k < len - 1; k++) // 不处理最后一个字符串终止符号
{
strEncode.AppendFormat(L"%%%02X", utf8[k] & 0xFF);
}
fLog.Write(strEncode, strEncode.GetLength() * 2);
}
}
fLog.Close();
}
return L"";
}
为了测试转码是否有问题,采用了先判断是否需要编码,然后对单个字符转码后写入文件的方式.1024*1024用 notepad2 打开完全不行,用notepad打开也有点勉强.等有时间了再把所有字符编码都打出来看.
参考链接:
字符串编码之间的转换(GB2312UTF8Unicode)及URLEncoding
URL编码与解码
VC++(unicode)实现URLDecode函数,对URl编码的字符串进行解码