相信大家很多人跟我一样,对于编码一直感觉云山雾罩,说知道吧?就知道gb2312是中文编码,一看见乱码,就知道是编码出了问题,但是是哪儿出问题,为什么出问题,除了蒙,还是蒙。尤其是弄好了之后,有人问:为什么呢。自己也不知道,就说:反正就是这样的,用什么编码就用什么解码。为什么,鬼知道。
    其实问题还是理解了之后,才能真正的明白为什么会这样,而且编码这个问题,也不是那么深奥,在网上搜索了一些资料,算是一直以来对编码问题的一个解决吧,最让人明白的资料有两个,第一个:
http://www.cnblogs.com/KevinYang/archive/2010/06/18/1760597.html
这个关于编码,我认为是最清楚的了,刚开始看完之后,觉得自己是真明白了,gb2312只是一个字符集,而unicode是所有能用到的字符的一个总集,utf-8是一种编码。它的字符集就是unicode。而且unicode是全人类达成共识的巨大的字符集,包括了gb2312字符集。
    有了这个“底气”之后,就开始了自己的探索了:
1、用记事本一个写一个xml,如下:<?xml version="1.0" encoding="gb2312"?>
<root>
<person>hi,大 美女你好</person>
</root> 将这个记事本保存为utf-8格式,然后打开,乱码,想也没想,感觉就是:用utf-8编码的文件,用gb2312的去解码,有的utf-8字符gb2312都没有,肯定会出问题了(这个理解是错误的!!!)
2、用记事本一个写一个xml,如下:<?xml version="1.0" encoding="utf-8"?>
<root>
<person>hi,大 美女你好</person>
</root> 将这个记事本保存为ansi格式(在简体中文的操作系统下,就是gb2312编码),然后打开,乱码???为什么呢?unicode编码不是包含了gb2312的字符集吗?按说应该能解析啊???(延续了第一个的想法,仅仅以字符集的大小去判断,还是错误的)
     没办法,只能继续网上找答案了,于是第二个资料出现了。
http://social.msdn.microsoft.com/Forums/zh-CN/2212/thread/f656ec85-2cd0-4d6a-a207-fe30523cc5a4/
对于这个问题是这样说的:“UTF-8中包含所有 gb2312 中的字符的定义  但是 每个字符的编号却不是完全对应 的 所以就会出现页面的中文字不能对应 的情况”
答案详见4楼Raymond Tang 版主的答案。
这样的话,就可以解释了为什么utf-8解析不了gb2312中的字符了。
    但是,我觉得这个答案还是有问题,像Raymond Tang版主所说,“每个字符的编号却不是完全对应 的”,他的意思,应该是gb2312中的编码和utf-8的编码编号是不一样的,所以不能解析出正确的字符。而如果仅仅是编码不一样,那至少也不会变化太大,应该是差不多还是个汉字吧?为啥成乱码呢?
    于是,我又仔细看了看第一篇文章,感觉发现了问题的所在:“GB2312以及GBK字符集,限定了使用最多2个字节来编码所有字符,并且规定了字节序。这样的编码系统通常用简单的查表,也就是通过代码页就可以直接将字符映射为存储设备上的字节流了。”,而:“虽然每个字符在Unicode字符集中都能找到唯一确定的编号(字符码,又称Unicode码),但是决定最终字节流的却是具体的字符编码”,这时,就由utf-8来决定了。简单的来说,就是字符流被打乱了,utf-8是变长编码的,它不能按照gb2312那样解析字节流。所以出现了乱码。
    所以,终归到底,unicode是包含了gb2312中的字符集,但是每种编码解码方式不一样,也就是说,utf-8编码是一种规则,他自己编码的字节流,需要用自己的规则去解码,如果不一致,就会出现乱码情况。这就是根源所在。    期间还发现了个挺有趣的事情:当新建文本文档只输入“联通”2字保存再打开时将是乱码。
    详见:http://baike.baidu.com/view/1273097.htm    这个帖子是我自己的一个总结,以备啥时候忘了能提醒自己,同时希望能对像我一样不明白的一些童鞋有些帮助,让那些早就深刻理解这些东西的人来说见笑了
    如果我理解的还是有什么偏差,希望大家能够指正。谢谢。
    

解决方案 »

  1.   

    +1编码是很重要的知识。所以Windows程序设计一上来就讲编码。以前没有体会,所以不明白为什么一本讲Windows程序设计的书开篇讲编码。
      

  2.   

    不要随意的选择Unicode或者UTF-8编码,在这样的编码下,所有的短字符(a-zA-Z等)都会占用2字节。会增加网络贷宽的消耗。
      

  3.   

    高级JS程序员,都会选择ANSI,也就是GB2312编码,这样的编码写的文件,短字符只占一字节
    然后把所有的中文字符写入另一个JS文件,所有文件都调用这个JS文件内容来输出中文信息。一般还不会使用gzip压缩,gzip压缩会降低浏览器的解吸效果。除非这个JS程序员对编码的意识并不清楚。
      

  4.   


    GB2312编码,这样的编码写的文件,短字符只占一字节
    Unicode或者UTF-8编码,在这样的编码下,所有的短字符(a-zA-Z等)都会占用2字节。
    请教下 这是为什么? 我的理解怎么相反?
      

  5.   

    字符基础 -- ASCII, DBCS, Unicode  所有的 string 类都是以C-style字符串为基础的。C-style 字符串是字符数组。所以我们先介绍字符类型。这里有3种编码模式对应3种字符类型。第一种编码类型是单子节字符集(single-byte character set or SBCS)。在这种编码模式下,所有的字符都只用一个字节表示。ASCII是SBCS。一个字节表示的0用来标志SBCS字符串的结束。
      第二种编码模式是多字节字符集(multi-byte character set or MBCS)。一个MBCS编码包含一些一个字节长的字符,而另一些字符大于一个字节的长度。用在Windows里的MBCS包含两种字符类型,单字节字符(single-byte characters)和双字节字符(double-byte characters)。由于Windows里使用的多字节字符绝大部分是两个字节长,所以MBCS常被用DBCS代替。
      在DBCS编码模式中,一些特定的值被保留用来表明他们是双字节字符的一部分。例如,在Shift-JIS编码中(一个常用的日文编码模式),0x81-0x9f之间和 0xe0-oxfc之间的值表示"这是一个双字节字符,下一个子节是这个字符的一部分。"这样的值被称作"leading bytes",他们都大于0x7f。跟随在一个leading byte子节后面的字节被称作"trail byte"。在DBCS中,trail byte可以是任意非0值。像SBCS一样,DBCS字符串的结束标志也是一个单字节表示的0。
      第三种编码模式是Unicode。Unicode是一种所有的字符都使用两个字节编码的编码模式。Unicode字符有时也被称作宽字符,因为它比单子节字符宽(使用了更多的存储空间)。注意,Unicode不能被看作MBCS。MBCS的独特之处在于它的字符使用不同长度的字节编码。Unicode 字符串使用两个字节表示的0作为它的结束标志。
      单字节字符包含拉丁文字母表,accented characters及ASCII标准和DOS操作系统定义的图形字符。双字节字符被用来表示东亚及中东的语言。Unicode被用在COM及Windows NT操作系统内部。
      你一定已经很熟悉单字节字符。当你使用char时,你处理的是单字节字符。双字节字符也用char类型来进行操作(这是我们将会看到的关于双子节字符的很多奇怪的地方之一)。Unicode字符用wchar_t来表示。Unicode字符和字符串常量用前缀L来表示。例如:wchar_t wch = L''1''; // 2 bytes, 0x0031
    wchar_t* wsz = L"Hello"; // 12 bytes, 6 wide characters字符在内存中是怎样存储的  单字节字符串:每个字符占一个字节按顺序依次存储,最后以单字节表示的0结束。例如。"Bob"的存贮形式如下:
    42  6F  62  00
    B  o  b  BOSUnicode的存储形式,L"Bob"
    42 00  6F 00  62 00  00 00
    B  o  b  BOS使用两个字节表示的0来做结束标志。  一眼看上去,DBCS 字符串很像 SBCS 字符串,但是我们一会儿将看到 DBCS 字符串的微妙之处,它使得使用字符串操作函数和永字符指针遍历一个字符串时会产生预料之外的结果。字符串"" ("nihongo")在内存中的存储形式如下(LB和TB分别用来表示 leading byte 和 trail byte)
    93 FA  96 7B  8C EA  00
    LB TB  LB TB  LB TB  EOS
    EOS值得注意的是,"ni"的值不能被解释成WORD型值0xfa93,而应该看作两个值93和fa以这种顺序被作为"ni"的编码。
      

  6.   


    你使用一个记事本存储一些UTF-8的短字符,然后查看记事本的属性就知道到底占几个字节了,
    不过记事本存储的UTF-8会额外增加两字节做为标识,比如存储“00000”的UTF-8文本,文件会占12字节
      

  7.   

    楼主的总结还是有点混乱...字符集和字符集编码是各自独立的,不是一一对应的关系...简单地说,不同字符集可以用同一种字符集编码来编码,同一字符集也可以用不同字符集编码来编码...假如指定了不匹配的字符集编码就会出现所谓“乱码”...而某些字符集较大(如多字节字符集),用较小的字符集编码去编码(如单字节字符集ASCII)自然会丢失信息,也会出现所谓“乱码”...所以不是码乱而是人乱了...
      

  8.   

    utf8编码规则 http://blog.csdn.net/sandyen/archive/2006/08/23/1108168.aspx
    utf16-utf8 转换规律 http://www.cnblogs.com/baiefjg/archive/2009/03/20/1417995.html
      

  9.   

    “中文编码”怎么了?难道国际编码utf不比中文编码更高级吗?
      

  10.   

    老大短短两句话也很难懂,前半句貌似要说“中文编码”nb,但是后半句却说utf比中文编码高级,这到底啥意思呢?相信大家很多人跟我一样,对于编码一直感觉云山雾罩,说知道吧?就知道gb2312是中文编码
    =======================================
    其实我这句话的意思就是,我对gb2312了解的很少,仅仅知道他是中文编码而已,不知道有关它的更深入的东西。仅此而已....
      

  11.   

    嗯...说到gb2312,你“就知道gb2312是中文编码”还知道错了...我猜知道gb2312的大部分人其实都不知道...gb2312其实是字符集不是字符编码...gb2312采用的编码是euc-cn编码,只不过还是我上面提到的,很多人把字符集和字符编码混淆不清...unicode和utf也一样,很多人混淆不清...unicode是字符集,utf是字符编码,所以同样是unicode,也有utf-8、utf-7、utf-16、utf-32等很多种编码...
      

  12.   

    哈哈,是,就知道还知道错了。哈哈。gb2312是字符集,而不是编码。“gb2312采用的编码是euc-cn”这个还确实不知道...
      

  13.   

    把UTF-8与gb2312相提并论就是把人分为男人和老人.根本就不是同一概念.
    ANSI, UNICODE,UNICODE Big Endian, UTF-8是编码方式
    GB2312, GBK, BIG5等是字符集
    二者不能混谈
    人可以分男人,女人
    也可以分老人,小孩,等
    但不能分男人,老人这样分
      

  14.   

    我之前做过,foxpro整个项目的繁简转换工具,为了方便大陆与台湾的软件人员共同使用同一套源码.做过电子书能自己识别繁简字,并支持各个国家的语言,能识别ANSI, UNICODE,UNICODE Big Endian, UTF-8这些所有的编码方式.
      

  15.   

         感觉很奇怪。数字字母在UTF8里和ANSI是一样的,都是占1个字节。但是汉字在ANSI是2个字节。但是在UTF8里怎么变成了6个字节。用16进制查看了普通txt文件的(分别建立UTF-8/ANSI)
      

  16.   

       vrhero大哥, 请教一下,经常能看到一些比如65001(UTF-8),65000(UTF-7),936(GB2312).这些数字又代表了什么呢,是字符编码还是其他什么意思?
      

  17.   


    汉字“我”在ANSI下16进制为:CE D2 
    汉字“我”在UTF-8下16进制为:EF BB BF E6 88 91 为什么会偏差这么多。晕了。
      

  18.   

    那些数字就是所谓代码页,其实就是字符集的代码标识...大家都知道计算机处理整型数最快,所以计算机数据的标识一般都是整型数,自然字符集标识也是整型数...和字符编码无关...这就是不同字符集编码的规则了...ASCII字符集只有数字字母和控制符,数量非常小,基本ASCII还没用完128位,扩展ASCII也没用完256位,所以1个字节就足够表示了...加上ASCII字符集是所有系统都必不可少的,因此任何字符集都兼容ASCII...而汉字用1个字节存储显然是不可能的,即使是2个字节也表示不完,但是考虑到很多汉字其实是极少用到的,早期编码方案就不完整,也因此早期很多软件会发生缺少生僻字的现象...而Unicode字符集设计目的就是要涵盖全世界所有文字字符的,所以需要更多存储单位...但是编码又不同了,因为还要考虑存储空间、传输带宽和处理效率,所以Unicode有多种编码方案...6个字节的绝对不是UTF-8,UTF-8是用1-3个字节变长编码方案存储的...
      

  19.   

    另外...你提到了ANSI,ANSI是标准的意思,不是指特定的某个字符集,而是系统当前设定的字符集...如在英文系统里默认就是ASCII,而在简体中文系统里默认就是GB2312...
      

  20.   

    而在简体中文系统里默认就是GB2312
    ----------
    不太准确...早期简体中文系统里默认是GB2312,现在的系统默认是GBK...
      

  21.   

    研究研究c++里面的宽字符和多字节转换就明白了。utf8一个汉字编码为3个字节,gb2312一个汉字编码为两个字节。