读书人

编码有关问题关于gb2312和utf-8

发布时间: 2012-02-23 22:01:36 作者: rapoo

编码问题,关于gb2312和utf-8
相信大家很多人跟我一样,对于编码一直感觉云山雾罩,说知道吧?就知道gb2312是中文编码,一看见乱码,就知道是编码出了问题,但是是哪儿出问题,为什么出问题,除了蒙,还是蒙。尤其是弄好了之后,有人问:为什么呢。自己也不知道,就说:反正就是这样的,用什么编码就用什么解码。为什么,鬼知道。
其实问题还是理解了之后,才能真正的明白为什么会这样,而且编码这个问题,也不是那么深奥,在网上搜索了一些资料,算是一直以来对编码问题的一个解决吧,最让人明白的资料有两个,第一个:
http://www.cnblogs.com/KevinYang/archive/2010/06/18/1760597.html
这个关于编码,我认为是最清楚的了,刚开始看完之后,觉得自己是真明白了,gb2312只是一个字符集,而unicode是所有能用到的字符的一个总集,utf-8是一种编码。它的字符集就是unicode。而且unicode是全人类达成共识的巨大的字符集,包括了gb2312字符集。
有了这个“底气”之后,就开始了自己的探索了:
1、用记事本一个写一个xml,如下:

XML code
<?xml version="1.0" encoding="gb2312"?><root><person>hi,大 美女你好</person></root> 

将这个记事本保存为utf-8格式,然后打开,乱码,想也没想,感觉就是:用utf-8编码的文件,用gb2312的去解码,有的utf-8字符gb2312都没有,肯定会出问题了。。。(这个理解是错误的!!!)
2、用记事本一个写一个xml,如下:
XML code
<?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

这个帖子是我自己的一个总结,以备啥时候忘了能提醒自己,同时希望能对像我一样不明白的一些童鞋有些帮助,让那些早就深刻理解这些东西的人来说见笑了。。。
如果我理解的还是有什么偏差,希望大家能够指正。谢谢。


[解决办法]
学习了~~~~
[解决办法]
这个总结不错,学习了
[解决办法]
收藏一下.以后怕用得到.谢谢
[解决办法]
很好,加深了我的理解,多谢分享。
[解决办法]
太好了,楼主讲究。
[解决办法]
每次遇到这个问题的时候,都是更改编码方式,只要好了就完了,没深究过……谢谢楼主的分享。
[解决办法]
探讨
很好,加深了我的理解,多谢分享。

[解决办法]

[解决办法]
学习了。。。。。。。。UP
[解决办法]
收藏。。。。
[解决办法]
收藏。
[解决办法]
不错,学习了
------解决方案--------------------


果断收藏...
[解决办法]
学习 学习
[解决办法]
过来学习的!
这边还不是很懂,没什么可以发言的!
[解决办法]
不要随意的选择Unicode或者UTF-8编码,在这样的编码下,所有的短字符(a-zA-Z等)都会占用2字节。会增加网络贷宽的消耗。
[解决办法]
彻底的了解了一下,收藏。。。
[解决办法]
高级JS程序员,都会选择ANSI,也就是GB2312编码,这样的编码写的文件,短字符只占一字节
然后把所有的中文字符写入另一个JS文件,所有文件都调用这个JS文件内容来输出中文信息。

一般还不会使用gzip压缩,gzip压缩会降低浏览器的解吸效果。

除非这个JS程序员对编码的意识并不清楚。
[解决办法]
果断收藏...
感谢分享!
[解决办法]

收藏了。。。


[解决办法]
“联通”@@
被MS鄙视了。。
[解决办法]
顶,学习了
[解决办法]
楼主很细心。不错。
[解决办法]

探讨
高级JS程序员,都会选择ANSI,也就是GB2312编码,这样的编码写的文件,短字符只占一字节
然后把所有的中文字符写入另一个JS文件,所有文件都调用这个JS文件内容来输出中文信息。

一般还不会使用gzip压缩,gzip压缩会降低浏览器的解吸效果。

除非这个JS程序员对编码的意识并不清楚。

[解决办法]
顶一下18楼
[解决办法]
顶下,联通
[解决办法]
收藏下
[解决办法]
good good ...
[解决办法]
字符基础 -- 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 BOS

Unicode的存储形式,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"的编码。
[解决办法]
太好了,
[解决办法]
学习了。。。挺好的。
感谢楼主~~~
[解决办法]
总结的相当好。
[解决办法]
收藏了,谢谢lz
[解决办法]

探讨

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

[解决办法]
楼主的总结还是有点混乱...字符集和字符集编码是各自独立的,不是一一对应的关系...

简单地说,不同字符集可以用同一种字符集编码来编码,同一字符集也可以用不同字符集编码来编码...假如指定了不匹配的字符集编码就会出现所谓“乱码”...而某些字符集较大(如多字节字符集),用较小的字符集编码去编码(如单字节字符集ASCII)自然会丢失信息,也会出现所谓“乱码”...

所以不是码乱而是人乱了...
[解决办法]
mark!
[解决办法]
跟住顶楼收藏了谢谢

[解决办法]
明白了
[解决办法]
分享
[解决办法]
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
[解决办法]
不错,楼主辛苦了。
[解决办法]
感谢lz的分享
[解决办法]
不错收藏了。谢谢
[解决办法]
mark
[解决办法]
学习了,接分。
[解决办法]
编码问题很重要!
[解决办法]
学习了
[解决办法]
探讨

学习了~~~~

[解决办法]
我还以为只有我是改完后就不管了呢。
[解决办法]
这贴好////
[解决办法]
不错,主上继续努力
[解决办法]
学习
学习


[解决办法]
学习了~~~~
[解决办法]
qt经常用到这个,学习了
[解决办法]
探讨
相信大家很多人跟我一样,对于编码一直感觉云山雾罩,说知道吧?就知道gb2312是中文编码

[解决办法]
探讨
字符基础 -- ASCII, DBCS, Unicode

  所有的 string 类都是以C-style字符串为基础的。C-style 字符串是字符数组。所以我们先介绍字符类型。这里有3种编码模式对应3种字符类型。第一种编码类型是单子节字符集(single-byte character set or SBCS)。在这种编码模式下,所有的字符都只用一个字节表示。ASCII是SBCS。一个字节……



[解决办法]
嗯...说到gb2312,你“就知道gb2312是中文编码”还知道错了...我猜知道gb2312的大部分人其实都不知道...

gb2312其实是字符集不是字符编码...gb2312采用的编码是euc-cn编码,只不过还是我上面提到的,很多人把字符集和字符编码混淆不清...

unicode和utf也一样,很多人混淆不清...unicode是字符集,utf是字符编码,所以同样是unicode,也有utf-8、utf-7、utf-16、utf-32等很多种编码...
[解决办法]
学些 呵呵
[解决办法]
还是有点晕,理解的不是很深,
每次遇到乱码,及乱改一通,到网上搜搜代码,知道解决为止。
没有深究过。
[解决办法]
大美女 你号。。。
[解决办法]
学习了,非常不错!
[解决办法]
xthanks
[解决办法]
依然云里雾里~~
[解决办法]
写得很棒。。。。一直不太懂的问题。。
[解决办法]
好,收藏了~
[解决办法]
说白了,编码就是字形和数字之间的一组对应关系,同一个字形在不同的编码中对应不同的数字(当然也有可能相同)。

另外,编码和字符集也是两码事。
[解决办法]
学习了~~~~
[解决办法]
kankan
[解决办法]
一直感觉云山雾罩
[解决办法]
这个原来一直没注意。
[解决办法]
收藏了……
[解决办法]
把UTF-8与gb2312相提并论就是把人分为男人和老人.根本就不是同一概念.
ANSI, UNICODE,UNICODE Big Endian, UTF-8是编码方式
GB2312, GBK, BIG5等是字符集
二者不能混谈
人可以分男人,女人
也可以分老人,小孩,等
但不能分男人,老人这样分
[解决办法]
探讨

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

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

嗯...说到gb2312,你“就知道gb2312是中文编码”还知道错了...我猜知道gb2312的大部分人其实都不知道...

gb2312其实是字符集不是字符编码...gb2312采用的编码是euc-cn编码,只不过还是我上面提到的,很多人把字符集和字符编码混淆不清...

unicode和utf也一样,很多人混淆不清...unicode是字符集,utf是字符编码,所以同样是unico……

[解决办法]
探讨

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

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

------解决方案--------------------


另外...你提到了ANSI,ANSI是标准的意思,不是指特定的某个字符集,而是系统当前设定的字符集...如在英文系统里默认就是ASCII,而在简体中文系统里默认就是GB2312...
[解决办法]
而在简体中文系统里默认就是GB2312
----------
不太准确...早期简体中文系统里默认是GB2312,现在的系统默认是GBK...
[解决办法]

收藏了。。。

[解决办法]

果断收藏...
感谢分享!
[解决办法]
8错8错
[解决办法]
研究研究c++里面的宽字符和多字节转换就明白了。utf8一个汉字编码为3个字节,gb2312一个汉字编码为两个字节。
[解决办法]
受教了~~~
[解决办法]
编码问题,国际化,本地化问题

真正了解了还真不是一件容易事啊

多谢lz总结分享
[解决办法]
学习. . .
[解决办法]

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

那些数字就是所谓代码页,其实就是字符集的代码标识...大家都知道计算机处理整型数最快,所以计算机数据的标识一般都是整型数,自然字符集标识也是整型数...和字符编码无关……

[解决办法]
学习了!

读书人网 >C#

热点推荐