# 字符编码

## 位、字节、字符

* 位（bit b）指二进制中的一位，是二进制最小信息单位。   &#x20;
* 字节（Byte B）是计算机信息技术用于计量存储容量的一种计量单位。   &#x20;
* 字符（ Character ）是指计算机中使用的字母、数字、汗字和符号等。

## 字符集和字符编码

* 字符集（Charset）：是一个系统支持的所有抽象字符的集合。
* 字符编码（Character Encoding）：是一套法则，使字符集与计算机之间建立对应关系，就是将字符转换为计算机可以接受的数字代码。就是以二进制的数字来对应字符集的字符。

## 常用字符集

### ASCII

ASCII（American Standard Code for Information Interchange，美国信息交换标准代码）是基于拉丁字母的一套电脑编码系统。

ASCII字符集：主要包括控制字符（回车键、退格、换行键等）；可显示字符（英文大小写字符、阿拉伯数字和西文符号）。

ASCII编码：将ASCII字符集转换为计算机可以接受的数字系统的数的规则。**使用7位（bits）表示一个字符，共128字符。**

> ASCII只是为英语国家的人使用的编码，因为里面只是用到了英语常用的字符

![](https://timgsa.baidu.com/timg?image\&quality=80\&size=b9999_10000\&sec=1505479856914\&di=b49f4569d4c1dd9d03b261f9606820b0\&imgtype=0\&src=http%3A%2F%2Fs1.knowsky.com%2F20170221%2F4fdfzprpy1j41.jpg)

### ISO-8859-1

**ISO-8859-1编码是单字节编码，向下兼容ASCII**，是ASCII 的扩展的一种，其编码范围是0x00-0xFF，0x00-0x7F之间完全和ASCII一致，0x80-0x9F之间是控制字符，0xA0-0xFF之间是文字符号。

此字符集支持部分于**欧洲**使用的语言，包括阿尔巴尼亚语、巴斯克语、布列塔尼语、加泰罗尼亚语、丹麦语、荷兰语、法罗语、弗里西语、加利西亚语、德语、格陵兰语、冰岛语、爱尔兰盖尔语、意大利语、拉丁语、卢森堡语、挪威语、葡萄牙语、里托罗曼斯语、苏格兰盖尔语、西班牙语及瑞典语。

**Latin1是ISO-8859-1的别名，有些环境下写作Latin-1。**

### GB 2312

《信息交换用汉字编码字符集》是由中国国家标准总局1980年发布，1981年5月1日开始实施的一套国家标准，标准号是GB 2312—1980。

GB2312编码适用于汉字处理、汉字通信等系统之间的信息交换，通行于中国大陆；新加坡等地也采用此编码。中国大陆几乎所有的中文系统和国际化的软件都支持GB 2312。

**基本集共收入汉字6763个和非汉字图形字符682个。**

GB2312的出现，基本满足了汉字的计算机处理需要，它所收录的汉字已经覆盖中国大陆99.75%的使用频率。**对于人名、古汉语等方面出现的罕用字，GB2312不能处理，**&#x8FD9;导致了后来**GBK及GB 18030**汉字字符集的出现。

[GB2312简体中文编码表](http://www.knowsky.com/resource/gb2312tbl.htm)

### BIG5

Big5是在1984年由台湾13家厂商与台湾地区财团法人信息工业策进会为五大中文套装软&#x4EF6;**（宏碁、神通、佳佳、零壹、大众**）所设计的中文内码，所以就称为Big5中文内码。

大五码是使用繁体中文社群中最常用的电脑汉字字符集标准，共收录13,060个中文字，其中有二字为重覆编码。

### Unicode

总数已经超过了65535，所以2个字节的数字是不够用的。

**Unicode编码系统为表达任意语言的任意字符而设计**。它使用4字节的数字来表达每个字母、符号，或者表意文字(ideograph)。

Unicode 还不断在扩增， 每个新版本插入更多新的字符。直至目前为止的第六版，**Unicode 就已经包含了超过十万个字符。**

**Unicode是字符集，UTF-32/ UTF-16/ UTF-8是三种字符编码方案。**

### Unicode与utf8是什么关系？

Unicode是字符集，UTF-32/ UTF-16/ UTF-8是三种字符编码方案。

## 字符编码

### GB2312编码

[GB2312简体中文编码表](http://www.knowsky.com/resource/gb2312tbl.htm)

如何进行编码？

GB2312一个汉字用两个字节表示。

原则上，两个字节可以表示 256×256＝65536 种不同的符号。

考虑到汉字编码与其它国际通用编码，如ASCII 西文字符编码的关系，我国国家标准局采用了加以修正的两字节汉字编码方案，只用了两个字节的低7位。这个方案可以容纳 128×128=16384 种不同的汉字；

为了与标准ASCII码兼容，每个字节中都不能再用３２个控制功能码和码值为32的空格以及127的操作码。

**所以每个字节只能有94个编 码。这样，双七位实际能够表示的字数是：94×94＝8836个。**

> 注意为了与标准ASCII码兼容，每个字节中都不能再用３２个控制功能码和码值为32的空格（特殊字符位，33个）以及1码值为127的操作码（1个，backspace），所以128-33-1=94，所以仅剩下**94×94＝8836个。94个区，94个位。**

## 区位码、国标码、机内码

### 区位码

这个方阵实际上组成一个有94个区（编号由01到94），每个区有94个位（编号由01到94）的汉字字符集。

一个汉字所在的区号和位号的组合就构成了该汉字的"区位码"。其中，高两位为区号，低两位为位号。**这样区位码可以唯一地确定某一汉字或字符；**

反之，任何一个汉字或符号都对应一个唯一的区位码，没有重码。如“保”字在二维代码表中处于17区第3位，区位码即“1703 ”。

### 国标码

国标码是由区位码稍作转换得到，**是一个汉字国家标准的二进制编码。**

其转换方法为：先将十进制区码和位码转换为十六进制的区码和位码；

这样就得了一个与国标码有一个相对位置差的代码，再**将这个代码的第一个字节和第二个字节分别加上20H，就得到国标码。**

如：“保”字的国标码为3123H，它是经过下面的转换得到的：1703D－>1103H->+20H－>3123H。 （20h就是十进制的32，上文提到了“但为了与标准ASCII码兼容，每个字节中都不能再用32个控制功能码和码值为32的空格以及127的操作码”）

> 知识提示：
>
> * 十六进制中H，就是表示数值是以16进制表示的。
> * O为8进制；
> * D是10进制，一般简略掉；
> * B是二进制。
>
> 解析过程：\
> 1\. 1703 十进制的区位码，分别转为16进制 17十进制 =>11十六进制（11H），03十进制=> 03十六进制 （03H），即为1103H\
> 2\. 再将第一个字节和第二个字节分别加上20H，11H+20H = 31H，03H+20H=23H，即3123H

### 机内码

国标码是汉字信息交换的标准编码，但因其前后字节的最高位为0，与ASCII码发生冲突，如 “保”字，国标码为31H和23H，而西文字符“1”和“#”的SCII也为31H和23H，现假如内存中有两个字节为31H和23H；

这到底是一个汉字，还是两个西文字符“1”和“#”？于是就出现了二义性，显然，国标码是不可能在计算机内部直接采用的。

于是汉字的**机内码**采用变形国标码，其变换方法为：将国标码的每个字节都加上128，即将两个字节的最高位由0改1，其余7位不变，如：由上面我们知道，“保”字的国标码为3123H，前字节为00110001B，后字节为00100011B，高位改1为10110001B和10100011B 即为B1A3H，因此，保字的机内码就是**B1A3**H;。**机内码是一个汉字在计算机内部保存的编码。**

> Unicode与 UCS
>
> 国际标准化组织（ISO）、多语言软件制造商组成的统一码联盟。
>
> unicode，为了世界上大多数文字系统进行整理和编码。
>
> ISO组织也在做同样的事情， ISO开展了 ISO/IEC 10646项目，名字叫“ Universal Multiple-Octet Coded Character Set”，简称UCS。
>
> 后来，双方意识到世界不需要2套通用的字符集，所以双方开始进行整合，到unicode2.0时，unicode的编码和ucs的编码都基本一致。

## unicode编码与UTF

一个字符的Unicode编码是确定的。

但是在实际传输过程中，由于不同系统平台的设计不一致，以及出于节省空间的目的，对Unicode编码的实现方式有所不同。Unicode的实现方式称为Unicode转换格式（Unicode Translation Format，**简称为UTF**）。

**简单说UCS或Unicode只是定义了从0到1114112这些数字各自对应是什么字符，而计算机上是如何实现的就是由UTF决定的。**  <br>

UTF-8、 UTF-16、 UTF-32等都是Unicode的编码实现方式。

图：Unicode中的汉字片段

![](/files/-LfnTHedjF44sHeljuaT)

> 重要：Unicode中的汉字组成并不像GBK一样按照汉语拼音来的，并没有什么明显的规律，所以在UTF-8中，汉字要得到汉字的拼音的话是办不到的，这时候要把他转换成GBK，然后再获取汉字的拼音。

### UTF-8 编码方式（规则）

### ![](/files/-LfnTHefFeKEeqCyluEC)

> [UNICODE 区域对照表](http://blog.chinaunix.net/uid-10008293-id-2972268.html)
>
> 通过查看上面链接的区域对照表，中国属于`4E00-9FFF CJK Unified Ideographs 中日韓統一表意文字`
>
> 由上图可见属于0800-FFF中，
>
> UTF-8中汉字到底占几个字节？ 3个字节

### 手工把Unicode转为UTF-8的编码

1. “你好” 的unicode码 “ 20320 ” “ 22909 ”
2. 二进制: 100 111101 100000 , 101 100101 111101
3. 每个字从右往左填充 1110xxxx 10xxxxxx 10xxxxxx
4. 计算器二进制转换为16进制：E4  BD  A0 ,  E5 A5 BD

> 解析：
>
> 工具：[在线进制转换](http://tool.oschina.net/hexconvert)
>
> 1. 通过[Unicdoe【真正的完整码表】对照表（二）汉字Unicode表 ](http://blog.csdn.net/hherima/article/details/9045861)查找到 “你”的16进制为4F60 ，转换成十进制为20320， “好”的位置是十六进制是5960+1D = 597D ，转换成十进制为22909
> 2. “你好” 的unicode码 十进制分别为 “ 20320 ” “ 22909 ”
> 3. 转成二进制为00 111101 100000 , 101 100101 111101，从上图中汉字属于0800-FFF中，UTF-8字节流为`1110xxxx 10xxxxxx 10xxxxxx`
> 4. 每个字从右往左填充 1110xxxx 10xxxxxx 10xxxxxx（就是把xxx的）
>
> 11100100 10111101 10100000 ， 11100101 10100101 10111101\
> 5\. 采用在线转换工具，计算器二进制转换为16进制：E4 BD A0 , E5 A5 BD
>
> 练习把unicode转为UTF-8
>
> “北京” 的unicode码 “21271” , “20140”
>
> 第一步：计算器算出每个字的二进制
>
> 第二步：填充 1110xxxx 10xxxxxx 10xxxxxx
>
> 第三步：计算器二进制转换为16进制
>
> 第四步：16进制编辑填入结果，然后以UTF-8查看

### UTF-16

* UTF-16和上面提到的Unicode本身的编码规范是一致的。
* 所有字符的编码长度为16位，也即2个字节。
* 对ASCII字符来说，存储空间浪费严重。
* 不兼容ASCII。

### UTF的字节序和BOM

UTF-16编码每个字符占用了两个字节，在Macintosh (Mac)机和PC机上，对字节顺序的**理解是不一致的**。避免同一个文件造成错乱如何解决呢？

Unicode规范中推荐的标记字节顺序的方法是**BOM**（ Byte Order Mark ）。

> 在解释一个UTF-16文本前，首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E，“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”，那么这是“奎”还是“乙”？
>
> Unicode规范中推荐的标记字节顺序的方法就是BOM。

UTF-8不需要BOM来表明字节顺序，但可以用BOM来表明编码方式。

> BOM含义
>
> 开头字节 Charset/encoding
>
> **EF BB BF UTF-8**&#x20;
>
> FE FF UTF-16/UCS-2, little endian(UTF-16LE)
>
> FF FE UTF-16/UCS-2, big endian(UTF-16BE)
>
> FF FE 00 00 UTF-32/UCS-4, little endian.
>
> 00 00 FE FF UTF-32/UCS-4, big-endia

### **总结：**

* 区位码前两个位换成十六进制，然后后两位换成十六进制。
* 国际码=区位码（十六进制）＋2020H
* 机内码=国际码＋8080H
* 01-09区为特殊符号。

16-55区为一级汉字，按拼音排序。

56-87区为二级汉字，按部首/笔画排序。

10-15区 及88-94区则未有编码。

## 资料

[UNICODE与UTF-8的转换详解](http://blog.csdn.net/iefreer/article/details/4836844)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://phper.shujuwajue.com/ji-chu/zi-fu-chuan/zi-fu-bian-ma.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
