本文大量借鉴了https://www.cnblogs.com/notbecoder/p/4840783.html里面的内容
概述
什么是字符、字符集和字符编码?
字符指的是文字或者符号。
字符集指的是字符的集合,一般字符集是一个完备的字符库,里面的字符足够表意。
人与人之间用于交流的文字符号,计算机并不能理解,也不能处理。为了让人与计算机、计算机与计算机之间可以正常交流,人发明了各种计算机字符集、字符编码。
字符集只是字符的集合,里面的每个字符都会对应一个字符代码,如ASCII码中"a"对应数字97。但是字符代码不一定适合作网络传送、处理,有时字符须经过编码(encode)后才能应用,这就是字符编码。我们常用的ASCII码、GBK、GB2312等字符集,除了具有字符集层面的含义之外,还具有字符编码的意思(也就是字符代码和字符编码是一样的)。但我们常用的Unicode字符集(两个字节),根据不同的使用需要,会将字符重新编码,比如UTF8(不定长,1 ~ 8字节)、UTF16(不定长,2 ~ 4字节)、UTF32(定长,4字节)都是Unicode字符集的编码实现。
计算机中的字符集和字符编码
因为计算机只能理解二进制,计算机中,是使用二进制字节的方式表示字符。在计算机中建立一种编码模型需要下面四步:
1、要有一个字符库,确定这些字符足够表意。 比如ASCII字符集,已经足够表示英语,但不能表示中文,于是产生GB2312字符集。所以市面上有很多字符集,经常会出现乱码问题
2、第一层编码,给每个字符编个数字,英文叫Code Point 或 Code Position。比如ASCII字符集中,65表示“A”,97表示“a”。
3、第二层编码,确定表示字符的二进制位数(8位,16位,32位)。ASCII使用7位(01000001表示“A”),DBCS(双字节字符集)使用16位。
4、第三层编码,确定字符二进制值的存储格式(大端法,小端法)
常见的字符集和字符编码
ASCII编码
我们经常说ASCII时,包含了字符集和字符编码两种意思。ASCII码是英文字符集,使用一个字节编码一个字符(一开始的ASCII用7 bits表示一个字节,第8位空余),这套字符编码,已经可以完全涵盖英文字符。不过对于日文、韩文和汉字来说,是完全不够用的。所以很多国家发明了自己的字符集和字符编码,但一般都兼容了ASCII码。
ISO-8859编码
由于各公司、国家之间都有自己的字符集,同一个数值,在不同的字符集之间表示的符号可能不一样,这样在一台电脑上正常可以阅读的文件,到另外一台电脑可能就成了乱码。为了解决这个问题,ISO组织统一了一套标准字符集,就是ISO-8859.不过 ISO-8859 不是一个字符集,而是一系列扩充的ASCII码字符集。ISO-8859也是单字节字符集,用一个字节表示一个字符。
ISO/IEC 8859-1 (Latin-1) - 西欧语言
ISO/IEC 8859-2 (Latin-2) - 中欧语言
ISO/IEC 8859-3 (Latin-3) - 南欧语言。世界语也可用此字符集显示。
ISO/IEC 8859-4 (Latin-4) - 北欧语言
ISO/IEC 8859-5 (Cyrillic) - 斯拉夫语言
ISO/IEC 8859-6 (Arabic) - 阿拉伯语
ISO/IEC 8859-7 (Greek) - 希腊语
ISO/IEC 8859-8 (Hebrew) - 希伯来语(视觉顺序)
ISO 8859-8-I - 希伯来语(逻辑顺序)
ISO/IEC 8859-9(Latin-5 或 Turkish)- 它把Latin-1的冰岛语字母换走,加入土耳其语字母。
ISO/IEC 8859-10(Latin-6 或 Nordic)- 北日耳曼语支,用来代替Latin-4。
ISO/IEC 8859-11 (Thai) - 泰语,从泰国的 TIS620 标准字集演化而来。
ISO/IEC 8859-13(Latin-7 或 Baltic Rim)- 波罗的语族
ISO/IEC 8859-14(Latin-8 或 Celtic)- 凯尔特语族
ISO/IEC 8859-15 (Latin-9) - 西欧语言,加入Latin-1欠缺的芬兰语字母和大写法语重音字母,以及欧元(€)符号。
ISO/IEC 8859-16 (Latin-10) - 东南欧语言。主要供罗马尼亚语使用,并加入欧元符号。
GBK编码
GBK字符集是汉字字符集,每两个字节表示一个字符,兼容了ASCII码,属于定长编码。
Unicode字符集
上面介绍的字符集都属于本地字符集,在一国之内使用没问题,跨国就不行了。如果一个计算机只能识别ACSII码集,要展示汉字就乱码了。而且每个国家都使用自己的字符集的话,会经常遇到乱码问题,不利于信息的传输和知识的传播,对电脑和互联网的普及都会带来一定的阻碍。
所以Unicode字符集被发明了,Unicode又称为万国码,可以表示世界上各个国家的字符。但是Unicode只是定义了每个字符用什么数字表示,属于计算机编码模型中的第一层编码,在实际的存储和传输过程中,我们并不使用Unicode作为字符的编码,而一般是采用UTF-8编码,Unicode的一种实现方式。
UTF-8编码
UTF-8与Unicode有什么关系呢?
UTF,全称“Unicode Transformation Formats”。是Unicode的编码格式。UTF-8是变长编码,以一个字节为单位对Unicode字符进行编码。英文等ASCII码表中出现的字符用UTF-8表示的时候,仍然只会使用一个字节,所以在传输英文的时候,使用UTF-8会节省很多空间。
我们看看Unicode编码是如何转化为UTF-8编码的:
Unicode编码(十六进制) | UTF-8 字节流(二进制) |
---|---|
00000000 - 0000007F | 0xxxxxxx |
00000080 - 000007FF | 110xxxxx 10xxxxxx |
00000800 - 0000FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
00010000 - 001FFFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
00200000 - 03FFFFFF | 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
04000000 - 7FFFFFFF | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
“中国”两个汉字的Unicode编码为:4E2D 和 56FD。
“中国”两个汉字的UTF-8编码为:E4B8AD 和 E59BBD。
以“中”为例,UTF-8编码转化为二进制是:
1110 0100
10 111000
10 101101
去掉每个字节的头部,剩下的二进制串为 0100 1110 0010 1101,转化为16进制为4E 2D,正好是“中”的Unicode编码。
Unicode字符有几个字节
经常会困惑一个问题,Unicode字符占用几个字节?
Unicode字符一开始被发明的时候,只有两个字节(也就是UCS-2),但是到后面发现有一些汉字(比较冷僻的),Unicode的码点已经用完,无法表示了。后面ISO对Unicode编码进行了扩展(也就是UCS-4),用四个字节表示一个字符,这样就完全够用了。
- UTF-8属于变长编码,最大长度是6个字节, UTF-8的4个字节,可以表示0x10000-0x001FFFFF的Unicode(最多21位)。
4个字节以内,已经包含了Unicode所有字符。
5、6个字节表示的已经是非Unicode编码范围,属于UCS-4 编码。早期UTF-8规范也可以达到6字节序列,不过2003年11月UTF-8 被 RFC 3629 重新规范,只能使用原来Unicode定义的区域, U+0000到U+10FFFF。根据规范,这些字节值将无法出现在合法 UTF-8序列中。 - UTF-16属于变长编码,UTF-16是完全对应于UCS-2的,但是它通过一种代理机制(感兴趣可以自己去看看),用两个UTF-16码元也可以表示UCS-4字符集里面的字符。
- UTF-32属于定长编码,UTF-32是完全对应于UCS-4的
所以,Unicode到底用几个字节表示,取决于我们使用了它的哪种实现方式是(在选择文件的编码时,没有Unicode这个选项),是UTF-8,UTF-16,还是UTF-32。我们文件采用的编码方式是UTF-32,则Unicode是4个字节。