Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1620320
  • 博文数量: 441
  • 博客积分: 20087
  • 博客等级: 上将
  • 技术积分: 3562
  • 用 户 组: 普通用户
  • 注册时间: 2006-06-19 15:35
文章分类

全部博文(441)

文章存档

2014年(1)

2012年(1)

2011年(8)

2010年(16)

2009年(15)

2008年(152)

2007年(178)

2006年(70)

分类: C/C++

2007-04-26 13:13:24

   打开百度,你在搜索栏中输入“芙蓉妹妹”,你看到了什么?是不是看到了下面的东东?
  
    %DC%BD%C8%D8%C3%C3%C3%C3&cl=3

   哦,那么这个"%DC%BD%C8%D8%C3%C3%C3%C3"是什么玩意呢? 聪明的你可能已经猜到了,它就是“芙蓉妹妹”这四个字,那么为什么是这样的呢?
  
   网页中通过url传递后的参数就会将其编码,URL 编码是一种浏览器用来打包表单输入的格式. 浏览器从表单中获取所有的name和其中的值,将他们作为name/value参数编码, 移去那些不能传送的字符, 将数据排行等等,这些还取决于你用GET还是POST?作为URL的一部分或者分离地发给服务器. 不管哪种情况, 在服务器端的表单输入格式样子象这样:
   
   这是一个专门对地址栏里所传递的参数进行编码的规则。比如在参数中带有空格的话,传递参数时就会发生错误,而用URL编码过以后,空格变成了%20这样就不会发生错误了;另外中文字经编码后全是怪符号,有利于保密。这个编码后的字串提交给服务器后是不需要解码的,网页会自动识别。

   URL编码遵循下列规则:
   每对name/value由&符分开.每对来自表单的name/value由=符分开. 如果用户没有输入值给这个name,那么这个name还是出现,只是无值(象这样 "name=").任何特殊的字符(就是那些不是简单的七位ASCII,如汉字) 将以百分符%用十六进制编码. 当然也包括象 =, &, 和 % 这些特殊的字符.在输入区中的空格将以加号+显示.

因为表单输入是用这个URL编码传递给你的脚本的,在你用这些参数之前必须解码,虽然解码是个很普遍的 工作,但是你在用c语言从stdin中获取了这些参数之后,如果是汉字的话,你必须自己解码。那么如何解码呢?
请看下面的示例程序:

/* decodeurl.c */

#include
#include
#include


void url2char(unsigned char *surl, unsigned char *res);
int h2i(char *s);

int main()
{
    char str[] = "%DC%BD%C8%D8%C3%C3%C3%C3"; // 这个是url中的汉字编码结果
    char res[256];

    url2char(str, res); //解码
    printf("%s", res); // 打印解码后的汉字
   
    return 0;
}

/*将16进制表示的汉字编码解码为汉字, 该函数只适用于纯汉字字符串*/
void url2char(unsigned char *surl, unsigned char *res)
{
    unsigned char hex[256];
    int i, j, nlen;
    unsigned char tmp[3];

    // 首先去掉所有的百分号
    nlen = (int)strlen(surl);
    j = 0;
    for ( i = 0; i < nlen; i++ )
    {
        if ( surl[i] == '%' )
            continue;
        hex[j++] = surl[i];
    }
    hex[j] = 0;

    nlen = (int)strlen(hex);
    j = 0;
   // 将每2个16进制数转换成一个10进制数(打印出来就是汉字)
    for ( i = 0; i < nlen; i += 2)
    {
        tmp[0] = hex[i];
        tmp[1] = hex[i+1];
        tmp[2] = 0;
        res[j++] = h2i(tmp);
    }
    res[j] = 0;
}

int h2i(char *s)
{
  char *digits="0123456789ABCDEF";
  if (islower (s[0])) s[0]=toupper(s[0]);   /* 判断是否是小写字母,是则转换成大写 */
  if (islower (s[1])) s[1]=toupper(s[1]);
  return 16*(strchr(digits,s[0])-strchr(digits,'0'))
         + (strchr(digits,s[1])-strchr(digits,'0')); /* 返回相应十进制数 */
}
程序运行的结果是:
芙蓉妹妹

上面的是纯汉字的字符串的解码,如果字符串中含有英文字符或者其它的字符呢?
则用下面的方法解码:
void url2char(unsigned char *surl, unsigned char *res)
{
    int i, j, nlen;
    unsigned char tmp[3];

    nlen = (int)strlen(surl);

    j = 0;
    for ( i = 0; i < nlen; )
    {
        if ( surl[i] == '%' )//以%开头的是汉字或者其它特殊字符
        {
            tmp[0] = surl[i+1];
            tmp[1] = surl[i+2];
            tmp[2] = 0;
            i += 3;
            res[j] = h2i(tmp);
        }
        else // 英文字符,直接拷贝
        {
            res[j] = surl[i];
            i++;
        }
        j++;
    }
    res[j] = 0;
}

在一般的中文网页中,比如百度,用的gb2312字符集,百分号加上2个16进制数代表一个汉字,把两个16进制数转换成10进制数,而一个Ansi字符就是一个无符号的整数,所以这些整数以字符串的形式连续打印出来就是你想要的汉字。

本文参考了http://oss.lzu.edu.cn/blog/article.php?tid_269.html一文。

附:C/C++里怎样判断字符串中含有汉字

该部分来源于http://blog.chinaunix.net/u/553/showart_225299.html

看字符的编码规范;GB2312的汉字以大于0x80的字节开始


#include <stdlib.h>
  #include <stdio.h>
  #include <string.h>
   
  int first(unsigned char ch)
  {
      if(ch>=0xb0&&ch<=0xf7)
        return 1;
      else
        return 0;
  }
  int second(unsigned char ch)
  {
          if(ch>=0xa1&&ch<=0xfe)
        return 1;
      else
        return 0;
  }
  int check(const char* p)
  {
      int i=0;
      for(i=0;i<strlen(p)-1;i++)
            if(first(p[i])&&second(p[i+1]))
                return 1;
  return 0;
  }
   
   
  main()
  {
  const char* str= "sdfddfsdf";
  check(str)?puts("there has character!"):puts("there has none character!");
   
  }


适用于GB2312字符集,  
  可修改first和second函数,使适用于其他字符集:)

一种可能是小于0xb0而大于0x80   ,那是GB2312中的其他字符,而非汉字.包括西文...  
  另一种可能是乱码(该字符串因为未知的原因丢失了第二位,产生乱码)


阅读(4738) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~