unicode和utf-8的区别(UTF-8独特的编码方式有关)

GBK转成UTF-8乱码好理解,但是再转回来怎么变成了“锟斤拷锟斤拷锟斤拷锟叫癸拷锟斤拷”,这不科学,我来为大家讲解一下关于unicode和utf-8的区别?跟着小编一起来看一看吧!

unicode和utf-8的区别(UTF-8独特的编码方式有关)

unicode和utf-8的区别

GBK转成UTF-8乱码好理解,但是再转回来怎么变成了“锟斤拷锟斤拷锟斤拷锟叫癸拷锟斤拷”,这不科学。

1.这其实和UTF-8独特的编码方式有关,由于UTF-8需要对unicode字符进行编码,unicode字符集是一个几乎支持所有字符的字符集,为了表示这么庞大的字符集,UTF-8可能需要更多的二进制位来表示一个字符,同时为了不致使UTF-8编码太占存储空间,根据二八定律.

2.UTF-8采用了一种可变长的编码方式,即将常用的字符编码成较短的序列,而不常用的字符用较长的序列表示,这样让编码占用更少存储空间的同时也保证了对庞大字符集的支持。

3.正式由于UTF-8采用的这种特别的变长编码方式,这一点和其他的编码很不一样。比如GBK固定用两个字节来表示汉字,一个字节来表示英文和其他符号。

import java.io.UnsupportedEncodingException; public class EncodingTest { public static void main(String[] args) throws UnsupportedEncodingException { String srcString = "我们是中国人"; byte[] GbkBytes = srcString.getBytes("GBK"); System.out.println("GbkBytes.length:" GbkBytes.length); byte[] UtfBytes = srcString.getBytes("UTF-8"); System.out.println("UtfBytes.length:" UtfBytes.length); String s; for (int i = 0; i < srcString.length(); i ) { s = Character.valueOf(srcString.charAt(i)).toString(); System.out.println(s ":" s.getBytes().length); } } }

结果为:

GbkBytes.length:12UtfBytes.length:18我:3们:3是:3中:3国:3人:3

看到使用GBK进行编码,“我们是中国人”6个汉字占12个字节,而是用UTF-8进行编码则占了18个字节,其中每个汉字占3个字节(由于是常用汉字,只占3个字节,有的稀有汉字会占四个字节。)

UTF-8编码的读取方式也比较不同,需要先读取第一个字节,然后根据这个字节的值才能判断这个字节之后还有几个字节共同参与一个字符的表示。

对于某一个字符的UTF-8编码,如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的位数,其余各字节均以10开头。UTF-8最多可用到6个字节。

如表: 1字节 0xxxxxxx 2字节 110xxxxx 10xxxxxx 3字节 1110xxxx 10xxxxxx 10xxxxxx 4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 因此UTF-8中可以用来表示字符编码的实际位数最多有31位,即上表中x所表示的位。除去那些控制位(每字节开头的10等),这些x表示的位与UNICODE编码是一一对应的,位高低顺序也相同。 实际将UNICODE转换为UTF-8编码时应先去除高位0,然后根据所剩编码的位数决定所需最小的UTF-8编码位数。 因此那些基本ASCII字符集中的字符(UNICODE兼容ASCII)只需要一个字节的UTF-8编码(7个二进制位)便可以表示。

看到使用GBK进行编码,“我们是中国人”6个汉字占12个字节,而是用UTF-8进行编码则占了18个字节,其中每个汉字占3个字节(由于是常用汉字,只占3个字节,有的稀有汉字会占四个字节。)

UTF-8编码的读取方式也比较不同,需要先读取第一个字节,然后根据这个字节的值才能判断这个字节之后还有几个字节共同参与一个字符的表示。

对于某一个字符的UTF-8编码,如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的位数,其余各字节均以10开头。UTF-8最多可用到6个字节。

如表: 1字节 0xxxxxxx 2字节 110xxxxx 10xxxxxx 3字节 1110xxxx 10xxxxxx 10xxxxxx 4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 因此UTF-8中可以用来表示字符编码的实际位数最多有31位,即上表中x所表示的位。除去那些控制位(每字节开头的10等),这些x表示的位与UNICODE编码是一一对应的,位高低顺序也相同。 实际将UNICODE转换为UTF-8编码时应先去除高位0,然后根据所剩编码的位数决定所需最小的UTF-8编码位数。 因此那些基本ASCII字符集中的字符(UNICODE兼容ASCII)只需要一个字节的UTF-8编码(7个二进制位)便可以表示。

所以当我们将由GBK编码的12个字节试图用UTF-8解码时会出现错误,由于GBK编码出了不可能出现在UTF-8编码中出现的序列,所以当我们试图用UTF-8去解码时,经常会遇到这种不可能序列,对于这种不可能序列,UTF-8把它们转换成某种不可言喻的字符“�”,当这种不可言喻的字符再次以UTF-8进行编码时,他们已经无法回到最初的样子了,因为那些是UTF-8编码不可能编出的序列。然后这个神秘字符再转换成GBK编码时就变成了“锟斤拷”。当然,还有很多其他的巧合,可能正好碰到UTF-8中存在的序列,甚至原本不是一个字符的字节,可能是某个字的第二个字节和下一个字的两个字节,正好被识别成一个UTF-8序列,于是解码出一个汉字,当然这些在我们看来都是乱码了,只不过不是“锟斤拷”的样子。因为不可能序列更普遍存在,所以GBK转UTF-8再转GBK时,最常见的便是“锟斤拷”!

所以:以非UTF-8编码编码出的字节数组,一旦以UTF-8进行解码,通常这是一条不归路,再尝试将解码出的字符以UTF-8进行编码,也无法还原之前的字节数组。

相反地,其他的固定长度编码几乎都可以顺利还原。

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页