MDA/MDD/TDD/DDD/DDDDDDD
posts - 536, comments - 111, trackbacks - 0, articles - 0
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

utf-8还是GBK、java的编码问题

Posted on 2008-05-11 22:38 leekiang 阅读(1150) 评论(0)  编辑  收藏 所属分类: java
1,编码只是表示字符一种方式,字符还是那个字符,只不过其数值表示的不一样而已。字体、样式和用什么编码表示字符没有任何关系。不可能存在UTF-8达不到的效果。除非你处理字符串的方式有问题,例如后台程序写死了一个中文等于两个字节。或者你的css文件编码有问题。例如html用了UTF-8编码,而css文件用了GB编码,又没有用charset指定css的编码等等。而对于前台HTML来说,无论页面什么编码,JavaScript内建的字符串类型是UTF-16编码的,不存在任何问题。 UTF-8的编码是变长的,从1字节(兼容ASCII)到4字节不等。用UTF-8的好处是它能表示任意Unicode字符,而GBK/GB2312做不到,除了不能表示一些外国文字外,一些古老的中文(如康熙字典里的一些字)也不能表示,但在Unicode里就有。后来发展出的GB18030可以表示任意Unicode字符,也是变长编码,兼容GBK,最长4个字节。编码问题是很麻烦的事情,尤其是同一个系统中存在多种编码的情况。由于每种编码表示的字符范围有限,所以转码过程中有可能丢失字符信息。因此,如果你的程序着眼于全球市场,而不仅仅局限于中文用户,或者未来发展有这方面的需求,那么就应该坚持程序内部都使用同一种Unicode编码,如UTF-8,这样以后程序在国际化时就不会存在什么编码问题。
来源: http://news.csdn.net/n/20080509/115815.html

2,
ISO-8859-1. 这套标准完全和ASCII兼容,它使用8位二进制表示一个字符 —--- 刚好一个字节,其中最高位是0时的解释和ASCII一样,但最高位是1时则用于定义其它字符,这样就在保证和 ASCII兼容的同时又扩展了ASCII,可以多表示字符啦
对java中的编码,类加载,类路径查找,集合等机制的理解

3,
(转)谈谈我对Java中Unicode、编码的理解
此篇文章写得很清楚。
Java 中,StringgetBytes()方法就是对特定的字符串(unicode)按照给定的字符集进行编码(encode),new String()则可以按照某个字符集将字节流转换回unicodedecode
之所以你会经常看到new String(text.getBytes("ISO-8859-1"),"GBK")这句代码,是因为一个GBK的字节流被错误地以ISO-8859- 1的方式转换为Stringunicode)了!
如果系统误以为是其它编码格式,就有可能再也转换不回来了,因为编码转换并不是负负得正那么简单的

4,
ANSI和Unicode big endia:
我们在Windows系统中保存文本文件时通常可以选择编码为ANSI、Unicode、Unicode big endian
和UTF-8,这里的ANSI和Unicode big endia是什么编码呢?
Unicode、Unicode big endian和UTF-8编码的txt文件的开头会多出几个字节,分别是FF、FE(Unicode),FE、FF(Unicode big endian),EF、BB、BF(UTF-8)
例如"联通",如果保存为Unicode,则hex为ff fe 54 80 la 90
如果保存为Unicode big endian,则hex为fe ff 80 54 90 la
也就是说,在windows里,所谓的Unicode其实是Unicode little endian
ANSI:
对于简体中文windows操作系统,ANSI就是GBK

UCS有两种格式:UCS-2和UCS-4。顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节(实际上只用了31位,最高位必须为0)编码
说UCS-4中,高两个字节为0的码位被称作BMP
将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。在UCS-2的两个字节前加上两个零字节,就得到了UCS-4的BMP。而目前的UCS-4规范中还没有任何字符被分配在BMP之外。
所以目前UNICODE=UCS-2

big endian和little endian

big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big endian。如果将49写在前面,就是little endian。

“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,一个皇帝送了命,另一个丢了王位。

我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。

UTF编码

UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下:

UCS-2编码(16进制)UTF-8 字节流(二进制)
0000 - 007F0xxxxxxx
0080 - 07FF110xxxxx 10xxxxxx
0800 - FFFF1110xxxx 10xxxxxx 10xxxxxx

例如“汉”字的Unicode编码是6C49。6C49在0800-FFFF之间,所以肯定要用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是:0110 110001 001001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。

读者可以用记事本测试一下我们的编码是否正确。需要注意,UltraEdit在打开utf-8编码的文本文件时会自动转换为UTF-16,可能产生混淆。你可以在设置中关掉这个选项。更好的工具是Hex Workshop。

UTF-16以16位为单元对UCS进行编码。对于小于0x10000的UCS码,UTF-16编码就等于UCS码对应的16位无符号整数。对于不 小于0x10000的UCS码,定义了一个算法。不过由于实际使用的UCS2,或者UCS4的BMP必然小于0x10000,所以就目前而言,可以认为 UTF-16(确切的说,是utf16-BE)和UCS-2(也就是我们通常所说的UNICODE)基本相同。但UCS-2只是一个编码方案,UTF-16却要用于实际的传输,所以就不得不考虑字节序的问题。

UTF的字节序和BOM

UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字 节序。例如“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎” 还是“乙”?

Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:

在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。

这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。

UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

Windows就是使用BOM来标记文本文件的编码方式的。

UTF-8 是 1-4 字节变长编码方案;
JVM用的是UCS-2
String其实是由char拼起来的,对char进行int后得到的数字就是unicode码16进制换算后的值
例如
char   int    Unicode
1      49     0031
中    20013   4e2d
国    22269   56fd
Integer.toHexString((int)str.charAt(i))

Windows的内码也是Unicode
从http://www.fmddlmyy.cn/text6.html受益良多。

6,http://www.javaeye.com/topic/398782比较形象,
提到一个很著名的奇怪现象:当你在 windows 的记事本里新建一个文件,输入"联通"两个字之后,保存,关闭,然后再次打开,你会发现这两个字已经消失了,代之的是几个乱码!
但有错误
UTF应该是UCS Transformation Format,其中的T不是Transfer

7,
ASCII码表
http://learn.akae.cn/media/images/app-encoding.ascii.png

ISO-8859-1收录的字符除ASCII收录的字符外,还包括一些其他语言的文字符号和一些控制字符。欧元符号出现的比较晚,没有被收录在ISO-8859-1当中。

因为ISO-8859-1编码范围使用了单字节内的所有空间,在支持ISO-8859-1的系统中传输和存储其他任何编码的字节流都不会被抛弃。换言之,把其他任何编码的字节流当作ISO-8859-1编码看待都没有问题。这是个很重要的特性,MySQL数据库默认编码是Latin1就是利用了这个特性。Latin1是ISO-8859-1的别名

法语及芬兰语本来也使用ISO/IEC 8859-1来表示。但因它没有法语使用的 œ、Œ、 Ÿ 三个字母及芬兰语使用的 Š、š、Ž、ž ,故于1998年被ISO/IEC 8859-15所取代。(ISO 8859-15同时加入了欧元符号)



http://blog.cathayan.org/item/1765
http://hedong.3322.org/archives/000355.html

只有注册用户登录后才能发表评论。


网站导航: