计算机编码,unicode、gb等的理解

  • 本文参考:

  https://www.cnblogs.com/gavin-num1/p/5170247.html

  https://blog.csdn.net/iefreer/article/details/4836844

  http://www.fmddlmyy.cn/text6.html

  • 前述

  最早接触的编码是ASCII,后来常用到的有GB2312、GBK、UTF-8。没有深入了解过各种编码,糊里糊涂的一直在用UTF-8,每次项目开始启动的时候会要求项目组成员配置IDE为UTF-8,也还好,基本没有碰到什么问题。

  推荐链接,配置IDE编码为UTF-8:https://www.aliyun.com/jiaocheng/845302.html?spm=5176.100033.2.28.378d18f7wrpYDv

  之前信誓旦旦的说“一个字节是8位,一个汉字是两个字节十六位”,一个字节8位是对的,但是一个汉字可不一定是两个字节。那一个汉字几个字节呢?要看哪一种编码,一般GB系列编码下是两个字节,UTF-8编码下是三个字节。可以写一个简单的main方法测试一下。

    public static void main(String[] args) throws UnsupportedEncodingException {
        // 测试各种编码下汉字“一”占几个字节
        System.out.println(new String("").getBytes("GBK").length);
        System.out.println(new String("").getBytes("GB2312").length);
        System.out.println(new String("").getBytes("UTF-8").length);
        System.out.println(new String("").getBytes("UTF-16").length);
        System.out.println(new String("").getBytes("UTF-32").length);
    }

  运行结果:

2
2
3
4
4

   可以看到,GBK、GB2312编码下汉字“一”占用2个字节,UTF-8编码下占用3个字节,UTF-16、UTF-32编码下占用4个字节。所以,在谈论一个字符占用几个字节时,不能脱离具体编码。

  •   组织

  (1) 国际标准化组织(ISO),为各行各业指定标准化规范,其中包括“通用字符集”(Universal Character Set,简称UCS),比较出名的是ISO-8859-1
  (2) 统一码联盟,制定了一种可以对全球几乎所有语言文字进行编码的标准,并且开发了Unicode标准(The Unicode Standard)。

  •   ASCII
/*  
*    
ASCII(American Standard Code for Information Interchange,美国信息互换标准代码,ASCⅡ)是基于拉丁字母的一套电脑编码系统。
*  它主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646。 *    ASCII第一次以规范标准的型态发表是在1967年,最后一次更新则是在1986年,至今为止共定义了128个字符,其中33个字符无法显示(这是以现今
*  操作系统为依归,但在DOS模式下可显示出一些诸如笑脸、扑克牌花式等8-bit符号),且这33个字符多数都已是陈废的控制字符,控制字符的用途主要是
*  用来操控已经处理过的文字,在33个字符之外的是95个可显示的字符,包含用键盘敲下空白键所产生的空白字符也算1个可显示字符(显示为空白)。
*  引用自: http://ascii.911cha.com/
*/

    1个字节8位,位有两种状态0和1,所以1个字节能够有2^8种状态,也就是256种状态。从0000000到11111111。

    “上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码,一直沿用至今。

    ASCII码一共规定了128个字符的编码,比如空格“SPACE”是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。”

  •       ISO-8859-1
    ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。
    很明显,ISO-8859-1编码表示的字符范围很窄,无法表示中文字符。但是,由于是单字节编码,和计算机最基础的表示单位一致,所以很多时候,仍旧使用iso8859-1编码来表示。而且在很多协议上,默认使用该编码。比如,虽然"中文"两个字不存在iso8859-1编码,以gb2312编码为例,应该是"d6d0 cec4"两个字符,使用iso8859-1编码的时候则将它拆开为4个字节来表示:"d6 d0 ce c4"(事实上,在进行存储的时候,也是以字节为单位处理的)。而如果是UTF编码,则是6个字节"e4 b8 ad e6 96 87"。很明显,这种表示方法还需要以另一种编码为基础。
  •      ANSI

    ANSI是默认的编码方式。对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对Windows简体中文版,如果是繁体中文版会采用Big5码)。

    ANSI是在ASCII的基础上的扩展。

  •      GB2312/GBK

    这就是汉字的国标码,专门用来表示汉字,是双字节编码,而英文字母和ISO-8859-1一致(兼容ISO-8859-1编码)。其中GBK编码能够用来同时表示繁体字和简体字,而GB2312只能表示简体字,GBK是兼容GB2312编码的。

  •      Big5

    又称为大五码或五大码,是使用繁体中文(正体中文)社区中最常用的电脑汉字字符集标准,共收录13,060个汉字。主要用于台湾。

  •      UCS/Unicode

    UCS是Unicode的简称,根据维基百科全书(http://zh.wikipedia.org/wiki/)的记载:历史上存在两个试图独立设计Unicode的组织,即国际标准化组织(ISO)和统一码联盟。ISO开发了ISO 10646项目,Unicode协会开发了Unicode项目。

    UCS只是规定如何编码,并没有规定如何传输、保存这个编码。例如“汉”字的UCS编码是6C49,我可以用4个ascii数字来传输、保存这个编码;也可以用utf-8编码:3个连续的字节E6 B1 89来表示它。关键在于通信双方都要认可。UTF-8、UTF-7、UTF-16都是被广泛接受的方案。UTF-8的一个特别的好处是它与ISO-8859-1完全兼容。UTF是“UCS Transformation Format”的缩写。

  •      UTF-8

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

UCS-2编码(16进制) UTF-8 字节流(二进制)
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 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和UCS-2基本相同。但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来标记文本文件的编码方式的。

  

猜你喜欢

转载自www.cnblogs.com/muwangying/p/10042760.html