编码小记(未整理-持续更新)

----------------基本概念-------------------------------
一.位:
计算机存储信息的最小单位,称之为位(bit),音译比特,二进制的一个“0”或一个“1”叫一位。
二.字节
字节(Byte)是一种计量单位,表示数据量多少,它是计算机信息技术用于计量存储容量的一种计量单位,8个二进制位组成1个字节。在ASCII码中,一个标准英文字母(不分大小写)占一个字节位置,一个标准汉字占二个字节位置。
三.字符
字符是指计算机中使用的文字和符号,好比“一、二、三、A、B、C、~!·#¥%…*()+”等等。 java

-----------------经常使用的编码的简单分类(3类)---------------linux

单字节字符编码:
1. 编码标准:ISO-8859-1
2. 说明:
最简单的编码规则,每个字节直接做为一个 UNICODE 字符。好比,[0xD6, 0xD0] 这两个字节,经过 iso-8859-1 转化为字符串时,将直接获得 [0x00D6, 0x00D0] 两个 UNICODE 字符,即 "ÖÐ"。
反之,将 UNICODE 字符串经过 iso-8859-1 转化为字节串时,只能正常转化 0~255 范围的字符。windows

ANSI 编码:
1. 编码标准:GB2312,BIG5,Shift_JIS,ISO-8859-2等
2. 说明:
把 UNICODE 字符串经过 ANSI 编码转化为“字节串”时,根据各自编码的规定,一个 UNICODE 字符可能转化成一个字节或多个字节。编码

反之,将字节串转化成字符串时,也可能多个字节转化成一个字符。好比,[0xD6, 0xD0] 这两个字节,经过 GB2312 转化为字符串时,将获得 [0x4E2D ] 一个字符,即 '中' 字。操作系统

“ANSI 编码”的特色:
1. 这些“ANSI 编码标准”都只能处理各自语言范围以内的 UNICODE 字符。
2. “UNICODE 字符”与“转换出来的字节”之间的关系是人为规定的。unix

UNICODE 编码:
1. 编码标准:UTF-8,UTF-16(BE),UTF-16(LE)等
2. 说明:
与“ANSI 编码”相似的,把字符串经过 UNICODE 编码转化成“字节串”时,一个 UNICODE 字符可能转化成一个字节或多个字节。code

与“ANSI 编码”不一样的是:
1. 这些“UNICODE 编码”可以处理全部的 UNICODE 字符。
2. “UNICODE 字符”与“转换出来的字节”之间是能够经过计算获得的。orm

 

--------------------------------UTF编码简介---------------------------------
UTF-8:
1. 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。所以对于英语字母,UTF-8 编码和 ASCII 码是相同的。
2. 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一概设为10。剩下的没有说起的二进制位,所有为这个符号的 Unicode 码
3. 一种变长的编码方案,使用 1~6 个字节来存储ip

Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------+------------------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
0020 0000-03FF FFFF | 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
0400 0000-7FFF FFFF | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx内存

 

UTF-16:
1. 介于 UTF-8 和 UTF-32 之间,使用 2 个或者 4 个字节来存储,长度既固定又可变。
2. 对于 Unicode 编号范围在 0 ~ FFFF 之间的字符,UTF-16 使用两个字节存储,而且直接存储 Unicode 编号,不用进行编码转换
3. 对于 Unicode 编号范围在 10000~10FFFF 之间的字符,UTF-16 使用四个字节存储,具体来讲就是:将字符编号的全部比特位分红两部分,较高的一些比特位用一个值介于 D800~DBFF 之间的双字节存储,较低的一些比特位(剩下的比特位)用一个值介于 DC00~DFFF 之间的双字节存储。
4. 位于 0xD800~0xDFFF 之间的 Unicode 编码是特别为四字节的 UTF-16 编码预留的,因此不该该在这个范围内指定任何字符,也就是该范围内在unicode里面不存在对应的unicode编码
5. UTF-16 要求在制定 Unicode 字符集时必须考虑到编码问题,因此真正的 Unicode 字符集也不是随意编排字符的

Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
---------------------+----------------------------------------------------------------------
0000 0000-0000 FFFF | (xxxxxxxx xxxx xxxxx) - (xxxxxxxx xxxxxxxx)
0001 0000-0010 FFFF | (yyyyyyyy yyxxxxxx xxxxxxxx xxxxxxxx) - (110110yy yyyyyyyy 110111xx xxxxxxxx)


UTF-32:
1. 一种固定长度的编码方案,无论字符编号大小,始终使用 4 个字节来存储
2. 以容纳全部的 Unicode 字符,因此直接存储 Unicode 编号便可,不须要任何编码转换。浪费了空间,提升了效率


----------------------名词解释-----------------------
unicode:
1. Unicode是为整合全世界的全部语言文字而诞生的。任何文字在Unicode中都对应一个值, 这个值称为代码点(code point)。代码点的值一般写成 U+ABCD 的格式。
2. Unicode是由美国主要计算机制造商联盟指定的编码字符集,主要用于克服在建立多语言程序和国际化软件时使用的不一样编码字符集的混乱。 从版本1.1开始,Unicode严格保持与ISO / IEC 10646及其扩展兼容。 该联盟也是ISO工做的重要贡献者,以进一步发展ISO / IEC 10646
3. CJK就是中日韩的意思。Unicode为了节省码位,将中日韩三国语言中的文字统一编码

ucs-2 & ucs-4:
1. ucs全称是Universal Multiple-Octet Coded Character Set
2. UCS旨在可用于计算机系统和数据通讯中的内部数据表示
3. 文字和代码点之间的对应关系就是UCS-2(Universal Character Set coded in 2 octets)。 顾名思义,UCS-2是用两个字节来表示代码点,其取值范围为 U+0000~U+FFFF。
为了能表示更多的文字,人们又提出了UCS-4,即用四个字节表示代码点。 它的范围为 U+00000000~U+7FFFFFFF,其中 U+00000000~U+0000FFFF和UCS-2是同样的。
4. ucs-4结构分为 group plane row cell,每一部分占用一个字节,其中当group和plane为00(16进制)时,是和ucs-2相对应
5. UTF-16是彻底对应于UCS-2的
6. UCS-4最高位为0

BMP:
1. 基本多语言面板(Basic Multilingual Plane,简称 BMP)
2. UCS-2 = BMP = plane 00 of group 00


UTF:
1. UCS Transformation Format
2. UTF-八、UTF-16以及UTF-32都是UCS的具体实现,用来存储和传输以及表示
3. UTF-16保存的最小单位为2个字节,UTF-32保存的最小单位为4个字节,因此多字节的编码涉及到字节摆放顺序的问题(大小头)

BOM:
1. Byte Order Mark
2. 是用来标识字节顺序的,只存在于windows平台中,字节流开头的“FFFE”或者“FEFF”也被称为字符"ZERO WIDTH NO-BREAK SPACE"
3. windows平台下的UTF-8编码格式是默认会加上BOM,由于UTF-8不须要BOM来代表字节顺序,但能够用BOM来代表编码方式,“FFFE”在UTF-8中的表示为“EF BB BF”(UTF-16的BOM是FEFF),因此若是收到以“EF BB BF”开头的字节流,则代表这是UTF-8编码
4. UTF-16或者UTF-32能够不含有BOM

Big Endian(BE) & Little Endian(LE):
1. ucs-2或者ucs-4中规定的码点在以UTF-16或者UTF-32表示的时候,字节存放顺序的2种
2. 表现为unicode编码的数据中的前2个字节为 "FF FE(Little Endian)",其中windows平台下的默认的Unicode编码为Little Endian的UTF-16
3. 例如“汉”字的Unicode编码是6C49。那么写到文件里时,到底是将6C写在前面,仍是将49写在前 面?若是将6C写在前面,就是Big Endian。若是将49写在前面,就是Little Endian
大端,高位存储在内存地址的低位
小端,低位存储在内存地址的低位
4. unix或者linux相关的平台使用无bom的utf8做为标准的缘由是:一切皆文件,一切文件皆是流,一个流能够被任意的切断,独立解析,而不会改变含义。因此它不能有头,也不能有结尾。因为头根本不存在,因此bom不容许存在
5. windows平台使用带BOM的UTF-8编码的缘由是:系统缺省都是用户当前代码页(code page),当前代码页不是utf8,这样,utf8做为非当前代码页格式就没法识别


ASCII:
1.美国(国家)信息交换标准(代)码(America Standard Code for Information Interchange)
2.ISO-8859-1是单字节编码,是以8位做为一个表示单元,至关因而ASCII的扩展,是彻底兼容ASCII
3.Unicode只与ASCII兼容(更准确地说,是与ISO-8859-1兼容)

ANSI:
1. 美国国家标准协会(American National Standard Institite)
2. ANSI编码是指不一样地区或者国家的编码标准,好比GB23十二、GBK或者Big-5编码标准,通常都是使用2个字节来表示一个字符,但也有例外,好比GB18030编码标准中的一些汉字是用3个字节表示,不一样的ANSI编码是互不兼容的
3. 在windows或者linux中存在内码页(code page)的概念,也就是不一样的非unicode编码是存在不一样的页的,好比GBK编码在CP936页,UTF-8的代码页是65001
4. 在操做系统内部,好比windows系列的内码就是Unicode编码,是以UTF-16来表示的,只要安装了对应的代码页,则能够正确显示出字符,记事本中选择ANSI编码保存则是使用系统缺省的编码格式存储数据,能够经过修改系统的地区来达到修改缺省的编码格式
5. 内码是指操做系统内部的字符编码,微软通常将缺省代码页指定的编码说成是内码,在确认了内码后,系统将按照当前的缺省代码页去解释文本文件里的字节流


GB2312:
1. 用两个数来编码汉字和中文符号。第一个数称为“区”,第二个数称为“位”。因此也称为区位码
2. GB2312的原文仍是区位码,从区位码到内码,须要在高字节和低字节上分别加上A0
3. “啊”的区位码是1601,写成16进制是0x10,0x01。这和计算机普遍使用的ASCII编码冲突。为了兼容00-7f的ASCII编码,咱们在区位码的高、低字节上分别加上A0。这样“啊”的编码就成为B0A1,咱们将加过两个A0的编码也称为GB2312编码
(从区位码到内码须要在高、低字节上分别加上A0),可是GB2312的原文仍是区位码

 


-----------------误解纠正-----------------------
误解:“ISO-8859-1 是国际编码?”
非也。iso-8859-1 只是单字节字符集中最简单的一种,也就是“字节编号”与“UNICODE 字符编号”一致的那种编码规则。当咱们要把一个“字节串”转化成“字符串”,而又不知道它是哪种 ANSI 编码时,先暂时地把“每个字节”做为“一个字符”进行转化,不会形成信息丢失。而后再使用 bytes = string.getBytes("iso-8859-1") 的方法可恢复到原始的字节串。

误解:“Java 中,怎样知道某个字符串的内码?”
Java 中,字符串类 java.lang.String 处理的是 UNICODE 字符串,不是 ANSI 字符串。咱们只须要把字符串做为“抽象的符号的串”来看待。所以不存在字符串的内码的问题。
当 UNICODE 被支持后,Java 中的 String 是以字符的“序号”来存储的,不是以“某种编码的字节”来存储的,所以已经不存在“字符串的编码”这个概念了。只有在“字符串”与“字节串”转化时,或者,将一个“字节串”当成一个 ANSI 字符串时,才有编码的概念。
用每“一个字节”就是“一个字符”的转化方法,实际上也就等同于采用 ISO-8859-1 进行转化。所以,咱们经常使用 bytes = string.getBytes("iso-8859-1") 来进行逆向操做,获得原始的“字节串”。而后再使用正确的 ANSI 编码,好比 string = new String(bytes, "GB2312"),来获得正确的“UNICODE 字符串”。

 

-------------------------宽字符和窄字符(多字节字符)-------------------------------------
1. 有的编码方式采用 1~n 个字节存储,是变长的,例如 UTF-八、GB23十二、GBK 等;若是一个字符使用了这种编码方式,咱们就将它称为多字节字符,或者窄字符。

2. 有的编码方式是固定长度的,无论字符编号大小,始终采用 n 个字节存储,例如 UTF-3二、UTF-16 等;若是一个字符使用了这种编码方式,咱们就将它称为宽字符。

3. Unicode 字符集可使用窄字符的方式存储,也可使用宽字符的方式存储;GB23十二、GBK、Shift-JIS 等国家编码通常都使用窄字符的方式存储;ASCII 只有一个字节,无所谓窄字符和宽字符。