ASCII、Unicode,UTF-8编码的区别

Unicode

unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。码位就是可以分配给字符的数字。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。

UCS

通用字符集 (Universal Character Set,UCS) 是由ISO制定的ISO 10646 (或称ISO/IEC 10646) 标准所定义的标准字符集。UCS-2用两个字节编码,UCS-4用4个字节编码。

UNICODE与UCS实际上是两个不同组织的产物,为了编码一体化而进行协商,可以把unicode看做UCS-2的父集,UCS-4的子集,以为UNICODE只支持U+0FFFF-U+10FFFF的编码,而UCS-4支持31个平面。

https://www.jianshu.com/p/1a39be00f5b8

Unicode ASCII UTF-8 GBK关系

首先必须知道一个概念 - 字符集

计算机中的所有字符, 说到底都是用二进制的 0/1 排列组合来表示的, 因此就需要有一个规范来规定每个字符对应 0/1 排列组合, 这样的规范就是字符集.

Unicode, ASCII, GB2312, GBK 都是字符集. UTF-8不是!

ASCII

最早的计算机在设计时采用 8 个 bit 作为一个字节 - byte, 所以, 一个字节能表示的范围就是 00000000 到 11111111, 也就是 0 到 255, 一共 256 种状态, 每一个状态对应一个符号, 可以表示 256 个符号.

美国有关的标准化组织就出台了 ASCII 编码, 对英语字符, 数字以及部分符号与二进制位之间的关系, 做了统一规定, 一共规定了 128 个字符的编码. 只占用了一个字节的后面 7 位, 最前面一位统一规定为 0, 一直沿用至今.

每个 ASCII 编码占用一个字节, 即 8 bit.

如果加上最前面一位, 即后 128 个最前面一位为 1 的编码, 被称为扩展ASCII码. 显示英语用 前 128 个符号编码就够了, 但是用来表示其他语言是不够的. 比如, 在法语中, 字母上方有注音符号, 它就无法用 ASCII 码表示. 于是, 一些欧洲国家就利用字节中闲置的最高位编入新的符号. 比如, 法语中的 é 的编码为 130 (二进制10000010) . 这样一来, 这些欧洲国家使用的编码体系, 可以表示最多 256 个符号.

但是中文怎么办?

GBK与GB2312

如果要表示中文, 显然一个字节是不够的, 至少需要两个字节, 而且还不能和 ASCII 编码冲突, 所以, 中国制定了 GB2312 编码, 用来把中文编进去.

后来发现这 GB2312 还是不够用, 汉字实在是太多了, 于是国内程序员又对这个字符集进行了扩充, 总之最后扩充成了GBK标准, GBK 依旧使用两个字节表示一个汉字. GBK 是在 GB2312 基础上扩容后兼容 GB2312 的标准.

同理, 日文和韩文等其他语言也有这个问题. 为了统一所有文字的编码, Unicode 应运而生.

Unicode

它为每种语言中的每个字符设定了统一并且唯一的二进制编码, 能够使计算机实现跨语言、跨平台的文本转换及处理.

Unicode 与 ASCII 是兼容的, 通常用两个字节表示一个字符, 原有的英文编码从单字节变成双字节,只需要把高字节全部填为 0 就可以.

但是,这里就有一个问题, 这些英文字母只需要一个字节就能存储, 现在用两个字节, 文件的体积就可能要扩大两倍. 这没办法接受!
因此,Unicode 有了各种各样的实现形式,最出名的是UTF-8

UTF-8

UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式.
UTF-8 最大的一个特点, 就是它是一种变长的编码方式. 它可以使用1~4个字节表示一个符号, 根据不同的符号而变化字节长度.

UTF-8 的编码规则

对于单字节的符号, 字节的第一位设为0, 后面7位为这个符号的 Unicode 码. 因此对于英语字母, UTF-8 编码和 ASCII 码是相同的.
对于 n 字节的符号 (n > 1) , 第一个字节的前 n 位都设为1, 第 n + 1 位设为 0, 后面字节的前两位一律设为 10. 剩下的没有提及的二进制位, 全部为这个符号的 Unicode 码.

举例
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

字符:

unicode

0x30103011

00110000
00010000

utf-8

0xe38090e38091
11100011
10000000
10010000

总结

Unicode, ASCII, GB2312, GBK 都是字符集. UTF-8不是. Unicode 只规定了符号的二进制代码, 并没有规定这个二进制代码应该如何进行存储. UTF-8 是则是 Unicode 储存的实现方式之一.
GB2312 是为了解决 ASCII 不支持中文的问题. GBK 是在 GB2312 基础上扩容后兼容 GB2312 的标准.

https://blog.csdn.net/weiwenjuan0923/article/details/52713387

摘要总结:

ASCII编码是128个字符

中国把汉字编入GB2312,Shift_JIS/Euc-kr各国标准…..

Unicode是为了解决各国乱码的,但浪费存储空间

UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6字节,英文字母是1字节,汉字通常是3字节,生僻字符是4-6字节

简单归纳:

编码 大小 支持语言

ASCII 1个字节 英文

Unicode 2个字节 (生僻字4个) 所有语言

UTF-8 1-6个字节,英文字母1个字节,汉字3个字节,生僻字4-6个字节 所有语言

具体解释:

最早只有127个字母被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码,比如大写字母A的编码是65,小写字母z的编码是122。

但是要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突,所以,中国制定了GB2312编码,用来把中文编进去。

你可以想得到的是,全世界有上百种语言,日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里,各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。

因此,Unicode应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。

Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符 (如果要用到非常偏僻的字符,就需要4个字节) 。现代操作系统和大多数编程语言都直接支持Unicode。

新的问题又出现了: 如果统一成Unicode编码,乱码问题从此消失了。但是,如果你写的文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间,在存储和传输上就十分不划算。

所以,本着节约的精神,又出现了把Unicode编码转化为"可变长编码"的UTF-8编码。

UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间。

UTF-8编码有一个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的一部分,

所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。

理论解释:

  1. ASCII码

在计算机内部,所有的信息最终都表示为一个二进制的字符串。

一个字节一共有256种不同的状态,从0000000到11111111。

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

ASCII码一共规定了128个字符的编码。这128个符号,只占用了一个字节的后面7位,最前面的1位统一规定为0。

  1. 非ASCII编码

扩展ASCII码在保留原始的7位的基础上,使用了最前的一位。

不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。

  1. Unicode

正如上一节所说,世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。

可以想象,如果有一种编码,将世界上所有的符号都纳入其中。

每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。

这就是Unicode,就像它的名字都表示的,这是一种所有符号的编码。

Unicode当然是一个很大的集合,现在的规模可以容纳100多万个符号。

每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字"严”。

Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

出现了两个严重的问题,

第一个问题是,如何才能区别Unicode和ASCII?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?

第二个问题是,英文字母只用一个字节表示就够了,如果Unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍。

  1. UTF-8

UTF-8就是在互联网上使用最广的一种Unicode的实现方式。UTF-8是Unicode的实现方式之一。

UTF-8最大的一个特点,就是它是一种变长的编码方式。

它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8的编码规则很简单,只有二条:

  1. 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

  2. 对于n字节的符号 (n>1) ,第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

  1. Unicode与UTF-8之间的转换
  1. ANSI是默认的编码方式。

对于英文文件是ASCII编码,对于简体中文文件是GB2312编码。(繁体中文版会采用Big5码)

  1. Unicode编码指的是UCS-2编码方式,即直接用两个字节存入字符的Unicode码。little endian格式

  2. Unicode big endian编码格式

  3. UTF-8编码方式

首先我们要明确 UTF-8 (8-bit Unicode Transformation Format) 是在统一码 (Unicode) 基础上细化并优化后的一种长度可变的字符编码方式,它是实现 Unicode 的方式之一,除了 UTF-8,还有UTF-16,UTF-32 等都可以实现 Unicode,但是 UTF-8 相对而言是用的最为广泛的。

UTF-8 可以使用1到4个字节来表示字符,它通过自身的规则能够灵活地变化长度来存储 Unicode 字符。

Unicode是两个字节吗?

Unicode只是定义了一个庞大的、全球通用的字符集,并为每个字符规定了唯一确定的编号,具体存储为什么样的字节流,取决于字符编码方案。推荐的Unicode编码是UTF-16和UTF-8。

你应该记住的一个UTF-8字符「EF BF BD」

发表于2015-03-28 utf-8是一种变长 (1 byte ~ 6 bytes) 的unicode字符集编码方案。所谓编码方案即讲字符集到码点 (code point) 的映射方式。

在众多的utf-8码点值中,除了ascii,你还应该记住「EF BF BD」,因为它是很多编程语言以及库中的备胎,即无效的码点值在编码的时候会默认用这个码点值进行替换,即utf-8中的超级「备胎」(REPLACEMENT CHARACTER)。

为什么会有无效的码点值? UTF-8 Code Point

从上图可以知道,utf-8编码 并非连续的 。很多人会忽略这个细节。

什么时候会遇到无效的utf-8码点? 当你试图把一个无效的码点值作为utf-8码点处理时,就会产生无效的码点。此时,无效的码点会被替换为「EF BF BD」,然后进行后续处理,以避免无效码点可能引起的异常。很多语言对这种处理是 自动进行 的,比如golang:

now := time.Now().Unix() // 一个无效的码点值 str := string(now) // golang是utf-8编码,会对无效码点进行替换 fmt.Printf("%X”, []byte(str)) // EFBFBD,即字符「�」 now := time.Now().Unix() // 一个无效的码点值 str := string(now) // golang是utf-8编码,会对无效码点进行替换 fmt.Printf("%X”, []byte(str)) // EFBFBD,即字符「�」 为什么要记住这个码点 在「字符集敏感」的环境中,如果你的数据中出现了「EF BF BD」就应该警惕了,因为你传输的数据中途很可能经过了自动替换,收到的数据未必是原始的数据。这对于你排查一些奇怪的数据交换不一致问题是很有用的,很多时候,可能是你的最后一颗救命稻草。

例如,使用utf-8编码的xml文档进行数据交换,如果看见了「�」,毫无疑问数据源有非法码点值。网页中出现了「�」,那么肯定是html文档的编码不是合规的utf-8编码文档。文本编辑器中出现了「�」,那一定是你打开这个文档的姿势不对——又选错编码了。总之,当你看见超级备胎「�」的时候,不要觉得大事不妙,不要像遇到一般乱码那样惊慌失措,你应该轻轻弹一下鼠标上的灰尘,将之打回原形。

因为aws的账单,才意识到自己的vps已经很久没有折腾了,博客也已经长草,应该说已经长成灌木丛了。

这才意识到自己已经回成都快9个月了。

有人说,时间是把杀猪刀。这很公平。但是,即使哪天挨上了这杀猪刀,也希望自己是头优雅的猪。

而此时,2015已经过去1/4.

–EOF–


https://liudanking.com/golang/utf-8_replacement_character/

参考链接1: http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

https://my.oschina.net/darionyaphet/blog/221124

http://blog.csdn.net/u012223913/article/details/51772610

参考链接2: http://blog.csdn.net/u012223913/article/details/51772610 http://www.cnblogs.com/malecrab/p/5300503.html

http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html