uri编码简析与C语言实现

1、编码原理

1、uri只允许可打印字符,如0-9、a-z、A-Z,保留原字符
2、对于不可打印字符,需要将该字符串转为它对应的16进制显示出来,用’%‘表示16进制,如0xE4表示为%E4
3、某些特殊字符如’+‘是表示为空格’ '还是保留原字符,取决于每个库自己的实现方式。
总结:对字符串进行uri编码时,会逐个字符进行编码,每个字符均表示为其16进制,具体显示为%XX特殊的:如’a’的16进制是0x61,可以表示为%61,但因为它是可见字符,则保留为原样。

2、C代码实现

注:代码主要是针对于glib2库的g_filename_to_uri()精简,注释是自己的理解,有错请指出。

1、uri-encode.h

#ifndef URI_ENCODE_H
#define URI_ENCODE_H

char *encodeUri(const char*oriString);

#endif

2、uri-encode.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "uri-encode.h"

const unsigned char acceptable[96] = { 
  /* A table of the ASCII chars from space (32) to DEL (127) */
  /*      !    "    #    $    %    &    '    (    )    *    +    ,    -    .    / */
  0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C,
  /* 0    1    2    3    4    5    6    7    8    9    :    ;    <    =    >    ? */
  0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20,
  /* @    A    B    C    D    E    F    G    H    I    J    K    L    M    N    O */
  0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
  /* P    Q    R    S    T    U    V    W    X    Y    Z    [    \    ]    ^    _ */
  0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F,
  /* `    a    b    c    d    e    f    g    h    i    j    k    l    m    n    o */
  0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
  /* p    q    r    s    t    u    v    w    x    y    z    {    |    }    ~  DEL */
  0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20
};

const char hex[16] = "0123456789ABCDEF";

#define MASK 0x8 /* Allows '/', '&', '=', ':', '@', '+', '$' and ',' */
#define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & MASK)) //判断字符(a)是保留还是转码

/* 1、ascii码在0-31之间的字符原样保留
 * 2、ascii码在32-127之间的字符做处理
 *      部分字符直接保留,eg: 0-9,a-z,A-Z,/,&,=,:,@,+,$,,
 *      部分字符需要转码,eg: 空格-> %20
 * @return 返回值为malloc的空间,非空时需要释放内存
 **/
 char *encodeUri(const char*oriString){
    int unacceptable = 0;
    int c;
    const char *p; 
    char *result,*q;

    if(!oriString)
        return NULL;

    //求需要转码的字符个数
    for(p=oriString; *p!='\0'; ++p){
        c = (unsigned char)*p;
        if(!ACCEPTABLE(c))
            ++unacceptable;
    }
    //求转码后字符串的长度,并分配内存
    result = malloc(p-oriString + unacceptable*2/*字母转码后需要占据3个字节空间*/ +1);

    for(q=result,p=oriString; *p!='\0'; ++p){
        c = (unsigned char)*p;
        /*针对32-127之间的部分字符进行转码*/
        if(!ACCEPTABLE(c)){
            *q++ = '%';         //转码以'%'开始
            *q++ = hex[c >> 4]; //(c >> 4) == (c/16)
            *q++ = hex[c & 15]; //(c & 15) == (c%16)
        }else
            *q++ = *p;
    }

    *q = '\0';

    return result;
}

3、main.c 用于对代码的检测验证

#include <stdio.h>
#include <stdlib.h>
#include "uri-encode.h"

int main (int argc, char * argv[])
{
    if(argc < 2){ 
        printf("usage: ./main \"string\"\n");
        exit(-1);
    }   

    char * encode = encodeUri(argv[1]); 
    printf("%s\n",encode);
    if(encode)	//释放
        free(encode);

    return 0;
}

3、编译运行

1、编译gcc main.c uri-encode.c uri-encode.h -o main
2、运行:(读者可参照输出认真理解第1步的编码原理)

输入输出
./main a盘+b卷a%E7%9B%98+b%E5%8D%B7 (可见代码中是直接保留了’+’)
./main \(a,b\)(a,b)

4、总结

1、编码的过程实际上是10进制转16进制,将字符的16进制表示形式存入字符数组的过程
2、编码是逐字节进行的,可见字符一般直接保留;不可见字符一般用%XX存储,其中XX是该字符的16进制表示

if(!ACCEPTABLE(c)){
    *q++ = '%';         //转码以'%'开始
    *q++ = hex[c >> 4]; //(c >> 4) == (c/16)
    *q++ = hex[c & 15]; //(c & 15) == (c%16)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值