URL中的字符只能是ASCII字符,但是ASCII字符比较少,而URL则常常包含ASCII字符集以外的字符,如非英语字符、汉字、特殊符号等等,所以要对URL进行转换。这个过程就叫做URL编码,或者叫URL转义,实质上就是将包含非ASCII字符的URL转换为有效的ASCII字符格式。
在进行URL编码时,每一个非ASCII字符都被替换为“%hh”格式,其中hh为两位十六进制数,它对应于该字符在ISO-8859-1字符集里的编码值。比如“中国”这两个汉字出现在URL,就要将他们转为“%D6%D0%B9%FA”,由于一个汉字需要两个字节,所以“中国”被替换成了四个ASCII字符。
转换代码入戏下:
/// 十六进制对应的字符
static unsigned char hexchars[] = "0123456789ABCDEF";
/**
* \brief 对url特殊字符进行编码
* \param s 输入字符串
* \param len 输入字符串长度
* \param new_length 输出字符串长度
* \return 输出编码后的url字符串,这段内存再使用完成以后需要释放
*/
char *url_encode(const char *s, int len, int *new_length)
{
register int x, y;
unsigned char *str;
str = (unsigned char *)malloc(3 * len + 1);
for(x = 0, y = 0; len--; x++, y++)
{
str[y] = (unsigned char) s[x];
if (str[y] == ' ')
{
str[y] = '+';
}
else if ((str[y] < '0' && str[y] != '-' && str[y] != '.')
|| (str[y] < 'A' && str[y] > '9')
|| (str[y] > 'Z' && str[y] < 'a' && str[y] != '_')
|| (str[y] > 'z'))
{
str[y++] = '%';
str[y++] = hexchars[(unsigned char) s[x] >> 4];
str[y] = hexchars[(unsigned char) s[x] & 15];
}
}
str[y] = '\0';
if (new_length) {
*new_length = y;
}
return ((char *) str);
}
void url_encode(std::string &s)
{
char *buf = url_encode(s.c_str(), s.length(), NULL);
if (buf)
{
s = buf;
free(buf);
}
}
//字符串转换整数
static inline int htoi(char *s)
{
int value;
int c;
c = ((unsigned char *)s)[0];
if (isupper(c))
c = tolower(c);
value = (c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16;
c = ((unsigned char *)s)[1];
if (isupper(c))
c = tolower(c);
value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10;
return (value);
}
/**
* \brief url字符串解码
* \param str 待解码的字符串,同时也作为输出
* \param len 待解码字符串的长度
* \return 解码以后的字符串长度
*/
int url_decode(char *str, int len)
{
char *dest = str;
char *data = str;
while (len--) {
if (*data == '+')
*dest = ' ';
else if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1)) && isxdigit((int) *(data + 2))) {
*dest = (char) htoi(data + 1);
data += 2;
len -= 2;
}
else
*dest = *data;
data++;
dest++;
}
*dest = '\0';
return dest - str;
}
/**
* \brief url字符串解码
* \param str 待解码的字符串,同时也作为输出
*/
void url_decode(std::string &str)
{
char buf[str.length() + 1];
strcpy(buf, str.c_str());
url_decode(buf, str.length());
str = buf;
}
/**
* \brief url字符串解码,并处理成符合json格式
* \param str 待解码的字符串,同时也作为输出
*/
void url_decode_json(std::string &str)
{
char buf[str.length() + 1];
strcpy(buf, str.c_str());
url_decode(buf, str.length());
//去掉前后的'\"'符号
if(buf[0] && buf[0] == '\"')
{
buf[0] = ' ';
}
unsigned int bufStrLen = strlen(buf);
if(bufStrLen && bufStrLen < sizeof(buf) && buf[bufStrLen-1] == '\"')
{
buf[bufStrLen-1] = ' ';
}
str = buf;
//去掉符号'\\'作为'\"'的前缀
std::string::size_type pos = 0;//位置
std::string strsrc = "\\\"";//要替换的字符串
std::string strdst = "\"";//目标字符串
std::string::size_type srclen = strsrc.size();//要替换的字符串大小
std::string::size_type dstlen = strdst.size();//目标字符串大小
while((pos = str.find(strsrc,pos)) != std::string::npos)
{
str.replace(pos,srclen,strdst);
pos += dstlen;
}
}
ASCII字符与URL编码的对照表如下
ASCII字符 URL编码
空格 %20
! %21
" %22
# %23
$ %24
% %25
& %26
' %27
( %28
) %29
* %2A
+ %2B
, %2C
- %2D
. %2E
/ %2F
0 %30
1 %31
2 %32
3 %33
4 %34
5 %35
6 %36
7 %37
8 %38
9 %39
: %3A
; %3B
< %3C = %3D > %3E
? %3F
@ %40
A %41
B %42
C %43
D %44
E %45
F %46
G %47
H %48
I %49
J %4A
K %4B
L %4C
M %4D
N %4E
O %4F
P %50
Q %51
R %52
S %53
T %54
U %55
V %56
W %57
X %58
Y %59
Z %5A
[ %5B
\ %5C
] %5D
^ %5E
_ %5F
` %60
a %61
b %62
c %63
d %64
e %65
f %66
g %67
h %68
i %69
j %6A
k %6B
l %6C
m %6D
n %6E
o %6F
p %70
q %71
r %72
s %73
t %74
u %75
v %76
w %77
x %78
y %79
z %7A
{ %7B
| %7C
} %7D
~ %7E
%7F
€ %80
%81
? %82
? %83
? %84
… %85
? %86
? %87
? %88
‰ %89
? %8A
? %8B
? %8C
%8D
? %8E
%8F
%90
‘ %91
’ %92
“ %93
” %94
? %95
– %96
— %97
? %98
? %99
? %9A
? %9B
? %9C
%9D
? %9E
? %9F
%A0
? %A1
¢ %A2
£ %A3
%A4
¥ %A5
| %A6
§ %A7
¨ %A8
? %A9
a %AA
? %AB
? %AC
ˉ %AD
? %AE
ˉ %AF
° %B0
± %B1
2 %B2
3 %B3
′ %B4
μ %B5
? %B6
· %B7
? %B8
1 %B9
o %BA
? %BB
? %BC
? %BD
? %BE
? %BF
à %C0
á %C1
? %C2
? %C3
? %C4
? %C5
? %C6
? %C7
è %C8
é %C9
ê %CA
? %CB
ì %CC
í %CD
? %CE
? %CF
D %D0
? %D1
ò %D2
ó %D3
? %D4
? %D5
? %D6
%D7
? %D8
ù %D9
ú %DA
? %DB
ü %DC
Y %DD
T %DE
? %DF
à %E0
á %E1
a %E2
? %E3
? %E4
? %E5
? %E6
? %E7
è %E8
é %E9
ê %EA
? %EB
ì %EC
í %ED
? %EE
? %EF
e %F0
? %F1
ò %F2
ó %F3
? %F4
? %F5
? %F6
÷ %F7
? %F8
ù %F9
ú %FA
? %FB
ü %FC
y %FD
t %FE
? %FF