理解字符编码

写代码这么久,忽然发现并不了解字符编码。咱们天天写下的代码,或者文件,在计算机中到底是怎样的存在?咱们都知道,计算机可以认识的只有 01。因此,不论任何数据,最终在计算机中只是 01 的排列组合。那么计算机时如何识别这些排列组合的呢?这就须要 字符编码(Character encoding)了。简单的说,就是按照必定的规则将信息与其对应的 01 的排列组合对应起来,这样计算机就能够根据字符编码识别出硬盘中的排列组合所表明的真实信息了。常见的 ASCII UTF-8 GBK 等等,都是典型的字符编码。计算机究竟是如何辨别这些字符编码的,就要看一下具体的字符编码原理。html

ASCII

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码),是基于拉丁字母的一套电脑编码系统。注意最后两个字母是 II,而不是罗马数字 2。ASCII 是由美国国家标准协会制定的,标准的单字节字符编码方案,用于基本文本的数据。起源于 50 年代后期,在 1967 年定案。它最初是美国国家标准,供不一样计算机在相互通讯时用做共同遵照的西文字符编码标准,它已被国际标准化组织定为国际标准,称为 ISO 646 标准。适用于全部拉丁文字字母。segmentfault

标准 ASCII 码使用单字符,即 8 个二进制位表示字符。第一位统必定为 0,实际使用后面 7 位来表示,因此 ASCII 码一共规定了 128 个字符的编码,包括全部的大小写字母,数字 0 到 9,标点符号以及一些特殊控制字符。windows

标准 ASCII 码表以下:微信

ASCII 是美国标准,并不能知足其余语言的需求。例如英镑符号,中文汉字等等。西方一些国家使用 8 个二进制位来表示字符,最多能够表示 256 个字符。显然,对于汉字而言,一个字符不可能知足需求。ui

ANSI

为了扩充 ASCII 编码,以用于显示本国的语言,不一样的国家和地区制定了不一样的标准,由此产生了 GB2312 , BIG5 , JIS 等各自的编码标准。这些使用 2 个字节来表明一个字符的各类汉字延伸编码方式,称为 ANSI 编码,又称为 MBCS(Muilti-Bytes Charecter Set,多字节字符集)。在简体中文系统下,ANSI 编码表明 GB2312 编码,在日文操做系统下,ANSI 编码表明 JIS 编码,因此在中文 windows下要转码成 gb2312 , gbk 只须要把文本保存为 ANSI 编码 便可。不一样的 ANSI 编码并不兼容,同一个二进制值在不一样的编码体系中可能表明不一样的字,这就致使了 Unicode 的诞生。在介绍 Unicode 以前,简单看一下 ANSI 中的中文编码。编码

GB2313

GB2312 也是 ANSI 编码里的一种,对 ANSI 编码最初始的 ASCII 编码进行扩充,为了知足国内在计算机中使用汉字的须要,中国国家标准总局发布了一系列的汉字字符集国家标准编码,统称为 GB码 ,或国标码。其中最有影响的是于 1980 年发布的《信息交换用汉字编码字符集 基本集》,标准号为 GB 2312-1980 ,因其使用很是广泛,也常被通称为国标码。GB2312 编码通行于我国内地;新加坡等地也采用此编码。几乎全部的中文系统和国际化的软件都支持 GB 2312操作系统

GB2312 是一个简体中文字符集,由 6763 个经常使用汉字和 682 个全角的非汉字字符组成。其中汉字根据使用的频率分为两级。一级汉字 3755 个,二级汉字 3008 个。code

GBK

GB2312 的出现,基本知足了汉字的计算机处理须要,可是对于人名,古汉语等方面的罕用字,GB2312 不能处理,这就致使了 GBK 的出现。orm

GBK 采用双字节表示,整体编码范围为 8140-FEFE ,首字节在 81-FE 之间,尾字节在 40-FE 之间,剔除 xx7F 一条线。总计 23940 个码位,共收入 21886 个汉字和图形符号,其中汉字(包括部首和构件)21003 个,图形符号 883 个。cdn

Unicode

ANSI 编码的缺点很明显,同一个编码值,在不一样的编码体系中表明着不一样的字符,很容易形成乱码。若是有一种编码,将世界上全部的符号都融入其中,每一个符号都有对应的编码值,这样就不存在乱码问题了。这就是 Unicode 编码。

Unicode 编码是一个很大的集合,如今的规模能够容纳 100 多万个符号,每一个符号的编码都不同。其实 Unicode 并非真正意义上的字符编码,它只是一个字符集,规定了符号的二进制码,却没有规定这个二进制码应该如何存储。Unicode 有一些具体的实现编码,其中用途最普遍的莫属 UTF-8

UTF-8

UTF-8 是使用最广的 Unicode 的一种 Unicode 的实现方式 ,它是一种变长的编码方式,使用 1 ~ 4 个字符表示一个符号,根据不一样的符号而变化字符长度,提升了 Unicode 的编码效率。先来看一下 UTF-8 对于不一样字节数的符号的表示方法, x 表明可以使用的二进制位:

字节数 编码规则 可表示字符数量
1 字节 0xxxxxxx 2的7次方 = 128
2 字节 11xxxxxx 10xxxxxx 2的11次方 = 2048
3 字节 1110xxxx 10xxxxxx 10xxxxxx 2的15次方 = 65536
4 字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 2的21次方 = 4194304

由上面的表很容易发现 UTF-8 的编码规则:

  • 对于单字节符号,第一位为 0,后面 7 为表示这个符号的 Unicode码。因此对于单字节符号,UTF-8 的表示方式与 ASCII 一致。

  • 对于 n 字节的符号,第一个字节的前 n 位都为 1,第 n+1 位为 0,后面的全部字节前两位均为 10,剩下的二进制位为这个字符的 Unicode码

使用这种变长编码方式,对于单字节的符号仅需使用一个字节来表示,不会形成浪费。对于汉字来讲,通常都是使用三个字符来表示。对于计算机来讲,也很容易区分一个字符到底占用几个字节:

  • 若是一个字节的第一位为 0,这个字节就是一个字符
  • 若是第一位为 1,连续有多少个 1,就表示当前字符占用多少个字节

除了 UTF-8,相应的还有 UTF-16。在 UTF-8 中,以 8 个二进制位表示一个字符,而在 UTF-16 中,以 16 个二进制位表示一个字符。16 个二进制位能够直接表示 65536 个字符,因此在 UTF-16 中,汉字和英文字母具备一样的地位,都是使用 16 个二进制位,即 2 个字节表示 1 个字符。对英文来讲会形成浪费,可是对中文来讲,能够节省存储空间。

关于字符编码,应该有了一个大概的认识,在平常使用中,咱们要尽可能作到编码的统一,避免出现乱码的状况。

参考文章:

文章同步更新于微信公众号: 秉心说 , 专一 Java 、 Android 原创知识分享,LeetCode 题解,欢迎关注!