字符编码:ASCII、Unicode、UTF-8

来源:互联网 发布:激光亚克力切割机软件 编辑:程序博客网 时间:2024/06/07 12:34

  互联网时代,知乎大V通过段子抖机灵,公众号大V通过鸡汤获得关注,微博大V通过新闻抢眼球,我们作为普通看客则刷的不亦乐乎。但是这些文章都有一个不引人注意的共同点,那就是它们都是由字符组成的(好吧,果然说的是废话☺)。字符君,也就是今天要讲的主角。

  这一篇篇排版精美、引人入胜的文章都是由一个个字符组成的,集字成句,集句成段,集段成文,最终呈现在我们面前。然而这些字符在计算机内部是怎样表示的,又是怎样显示在屏幕上的却没有多少人了解。其实计算机经过了这么多年的发展,字符编码都已经基本形成了国际通用的标准,各种IDE、浏览器、文字处理软件已经都帮我们处理好了,我们不再需要在字符编码方面下很多功夫了。但是作为一个程序猿我们必须得懂得一点字符编码的知识,这不仅是程序猿的专业素质,也是因为假如需要做应用国际化(Internationalization)的时候不会出现各种乱码了(%¥&*#@¥%……#%),话说在网上下载字幕导入视频中的时候偶尔也会出现乱码,需要我们用Nodepad++选择合适的编码格式才能正确的观看。


ASCII编码

  ASCII(American Standard Code for Information Interchange,美国信息交换标准代码),它主要用于显示现代英语和其他西欧语言。ASCII至今为止共定义了128个字符,其中包括95个可显示字符和33个无法显示的控制字符(多数都已经废除)。
  在计算机的最底层,所有的信息都是用二进制的串来表示的,每一个二进制位(bit)都有0和1两种状态,所以8个二进制位(一个字节byte)可以组合出256种状态。ASCII的128个字符,只占用了一个字节的后面7位,最高位(b7)一般用作奇偶校验位。

1968年版ASCII编码速见表
1968年版ASCII编码速见表

缺点:

  ASCII的局限在于只能显示26个基本拉丁字母、阿拉伯数目字和英式标点符号,因此只能用于显示现代美国英语。


  随着计算机在全世界的流行,使用计算机的人越来越多,不再局限于使用英语的地区,这时候ASCII编码的问题就出现了–只占用1个字节的ASCII编码最多只能表示256个字符,那要怎么才能表示其他的语言呢。要知道,仅仅只是《汉字大字典》中收录的汉字就有6万多个,更何况还有很多小地区都有着很多不同的文字。如果任由各个语言的人自行订立编码规则的话,那就会造成语言的壁垒了,可能出现广东的人收到北京的人的邮件一打开全是乱码的情况,因为广东编码并不兼容北京编码。-_-#
  所以需要出现一种很大容量的编码,将世界上所有的文字字符都囊括在内,每一个字符都能在其中找到独一无二的存在。这个时候,Unicode编码粉墨登场了。

Unicode编码

  Unicode(万国码、国际码、统一码)是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得电脑可以用更为简单的方式来呈现和处理文字。Unicode是一个很大的集合,现在的规模可以容纳100多万个字符,已经收入超过十万个字符,Unicode 是一个很大的集合,现在的规模可以容纳100多万个符号,每个符号的对应的二进制都不一样。Unicode 规定可以使用多个字节表示一个字符,例如 a 的编码为 01100001,一个字节就够了,汉字“好”的编码为 01011001 01111101,则需要两个字节。

为了兼容ASCII,Unicode 规定前0~127个字符与ASCII是一样的,不一样的只是128~255的这一段。完整的Unicode编码请查看:unicode.org。

问题:

  但是Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储,也就是并没有说明在计算机内部实现中二进制代码到底是长得什么样子。
  比如,汉字”强”的Unicode是十六进制数U+5F3A,转换成二进制数为0101 1111 0011 1010,这个字符的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。
  这里就有两个严重的问题:
  1.如何才能区别Unicode和ASCII或者其他编码呢?计算机怎么知道三个字节表示一个Unicode符号,还是分别表示的三个ASCII符号呢?
  2.如果Unicode统一规定,每个符号用四个字节的定长表示,而英文字母只用一个字节表示就够了,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。


  UTF-8就是在互联网上使用最广的一种Unicode的实现方式。其他实现方式还包括UTF-16(字符用两个字节或四个字节表示)和UTF-32(字符用四个字节表示),不过在互联网上基本不用。所以两者之间的关系是:UTF-8是Unicode的在计算机内部的实现方式之一

UTF-8

  UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码。它可以用来表示Unicode标准中的任何字符,且其编码中的第一个字节仍与ASCII兼容,这使得原来处理ASCII字符的软件无须或只须做少部分修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或发送文字的应用中优先采用的编码。
  
Unicode和UTF-8之间的转换关系表(X表示码点占据的位)

码点的位数 码点起值 码点终值 字节序列 Byte 1 Byte 2 Byte 3 Byte 4 7 U+0000 U+007F 1 0XXXXXXX 11 U+0080 U+07FF 2 110XXXXX 10XXXXXX 16 U+0800 U+FFFF 3 1110XXXX 10XXXXXX 10XXXXXX 21 U+10000 U+1FFFFF 4 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
UTF-8编码字节含义
  • 对于UTF-8编码中的任意字节B,如果B的第一位为0,则B独立的表示一个字符(ASCII码),形如0XXXXXXX;
  • 如果B的第一位为1,第二位为0,则B为一个多字节字符中的一个字节(非ASCII字符);
  • 如果B的前两位为1,第三位为0,则B为两个字节表示的字符中的第一个字节,形如110XXXXX 10XXXXXX;
  • 如果B的前三位为1,第四位为0,则B为三个字节表示的字符中的第一个字节,形如1110XXXX 10XXXXXX 10XXXXXX;
  • 如果B的前四位为1,第五位为0,则B为四个字节表示的字符中的第一个字节,形如11110XXX 10XXXXXX 10XXXXXX 10XXXXXX。

      因此,对UTF-8编码中的任意字节,根据第一位,可判断是否ASCII字符;根据前二位,可判断该字节是否为一个字符编码的第一个字节;根据前四位(如果前两位均为1),可确定该字节为字符编码的第一个字节,并且可判断对应的字符由几个字节表示;根据前五位(如果前四位为1),可判断编码是否有错误或数据传输过程中是否有错误。

      下面以汉字“强”为例子,演示一下如何从Unicode转换成对应的UTF-8编码:
      首先,从中日韩汉字Unicode编码表 查到“强”的Unicode码为U+5F3A(对应二进制表示为0101 1111 0011 1010),根据上文Unicode和UTF-8之间的转换关系表可知,“强”字处在第3行范围内,因此需要用3个字节进行存储,也即格式为“1110XXXX 10XXXXXX 10XXXXXX”。依次将“强”字对应的二进制表示从后向前填入格式中的X,多出的位补0。最终得到“强”字的UTF-8编码为11101010 10111100 10111010,转换成十六进制就是EABCBA。

优点:
  • ASCII是UTF-8的一个子集。因为一个纯ASCII字符串也是一个合法的UTF-8字符串,所以现存的ASCII文本不需要转换。为传统的扩展ASCII字符集设计的软件通常可以不经修改或很少修改就能与UTF-8一起使用。
  • UTF-8是可变长的编码,可以节省存储空间。
  • UTF-8字符串可以由一个简单的算法可靠地识别出来。就是说,一个字符串在任何其它编码中表现为合法的UTF-8的可能性很低,并且可能性随字符串长度增长而减小。
缺点:
  • 与其他Unicode编码相比,特别是UTF-16,在UTF-8中ASCII字符占用的空间只有一半,可是在一些字符的UTF-8编码占用的空间就要多出1/3,特别是中文、日文和韩文(CJK)这样的方块文字。

参考内容:
1.ASCII–维基百科(https://zh.wikipedia.org/wiki/ASCII)
2.Unicode–维基百科(https://zh.wikipedia.org/wiki/Unicode)
3.UTF-8–维基百科(https://zh.wikipedia.org/wiki/UTF-8)
4.字符编码笔记:ASCII,Unicode和UTF-8–阮一峰的网络日志(http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html)

0 0