常见的字符编码

字符:各种文字和符号的总称,包括各个国家的文字,标点符号,图形符号,数字等

字符集:字符集是多个符号的集合,每个字符集包含的字符个数不同

字符编码:字符集只是规定了有哪些字符,而最终决定采用哪些字符,每个字符用多少字节表示等问题,是由编码来决定的。因为计算机要准确的处理各种字符集文字,就需要对字符进行编码,以便于计算机的识别和存储。

ANSI在中国大陆称为GBK(以前是GB2312),最常用的是GBK和UTF-8无BOM编码格式。UTF-8、UCS-2 Big Endian(Unicode 大端)、USC-2 Little Endian(Unicode 小端)为有BOM头

BOM头:文本文件中开始的几个并不表示任何字符的字节,用二进制编辑器展示如下

UTF8的BOM头为0xEF 0xBB 0xBF
Unicode大端模式为0xFE 0xFF
Unicode小端模式为0xFF 0xFE
在这里插入图片描述

ASCII码

计算机只能识别数字,本质是通过二进制来表示十进制的所有数字,以此来换算数据进行计算。

如果使用数字来表示文本,就需要将数字和文本一一对应,且所有计算机都必须同一标准,否则就会造成同一段数字在不同计算机上显示的字符不同。至此,美国ANSI指定了一个标准,规定了常用字符的集合以及每个字符对应的编号,这就是ASCII字符集的诞生

当时的编解码系统:查表

编码步骤:字符→查表→对应的编码→存储设备

  1. 在ASCII字符集表中依次找到字符对应的字节

  2. 然后将对应的字节写入存储设备

解码步骤:

  1. 在ASCII字符编码表中依次找到字节编码对应的字符

  2. 然后将对应的字符输出到输出设备。

    • 0~31及127(共 33 个):是控制字符或通信专用字符(其余为可显示字符),如控制符:LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BS(退格)

    • 32~126(共 95 个):是字符(32 是空格),其中 48~57 为 0 到 9 十个阿拉伯数字。

    • 65~90 :为 26 个大写英文字母,97~122 号为 26 个小写英文字母,其余为一些标点符号、运算符号等

  • 后 128 个称为扩展 ASCII 码:许多基于 x86 的系统都支持使用扩展(或“高”)ASCII。扩展ASCII 码允许将每个字符的第 8 位用于确定附加的 128 个特殊符号字符、外来语字母和图形符号。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

OEM字符集

一个字节能够表示的数字有256个,但是ASCII字符集只表示了128个(0x00~0x7F),但是当时对于OEM没有明确的规定,导致各种计算机的后128位表示的字符也各种各样,这就导致了人们无法跨机器交流文档。

OEM就是对ASCII码的扩展,诞生的各种OEM字符集最终生成了MBCS多字节字符集

MBCS多字节字符集

ASCII和OEM都是单字节编码,即一个字节翻译一个字符,对于大部分使用拉丁语系得国家,都足够了,但是对于大部分亚洲国家,256个字符远远不够,例如中国。

既要和ASCII保持兼容,又要能够支持自己国家的字符,这就出现了多字节编码方式,相应得字符集就称为多字节字符集(Muilti-Bytes Charecter Set)

最常见双字节字符集:

  • 中文字符集GB2312:包含了所有简体字符以及一部分其他字符

  • 中文扩展字符集GBK:在GB2312的基础上,添加了繁体字符和其他非简体字符

windows系统采用936代码页对GBK字符集进行编解码

  • 在解析字节流的时候,如果遇到字节最高位为0,就用936代码页中的第一张码表进行解码(和单字节字符集解码方式一样)

  • 如果遇到字节最高位为1,就表示需要两个字节才能对应一个字符

举个例子:

GB2312编码写如下内容:我叫ABC

11001110 11010010 10111101 11010000 01000001 01000002 01000003

全角和半角:

全角占用两个标准字符(两个字节)的位置,半角为一个标准字符(字节)

三大标准

ANSI标准、国家标准、ISO标准

ANSI编码一般指代平台的默认编码,例如英文系统使用的就是ISO标准的ISO-8859-1,中文系统是GBK,,统称为ANSI编码。

国家标准一般是各个国家根据自身的实际情况规定的编码格式,例如:中国的GBK、GB2312和GB18030

ISO标准字符编码由ISO组织整理

Unicode字符集

根据上述的编码标准和编码字符集,已经能够满足在不同机器上查阅不同语言的文档

但是也存在问题:如果一份文档中含有不同国家不同语言的字符,我们无法在一份文档中显示所有字符

  • Unicode就是全人类达成共识而生成的一个巨大的字符集,并为每个字符进行同一编号,分配唯一的字符码

  • Unicode前128位和ASCII码一致,用于兼容ASCII码,Unicode的总范围是\x0\x10FFFF共1,114,112个码位

  • 2048个用于编码代理(UTF-16),66个非字符码位(例如BOM),137,468个预留给私人使用,最终剩余974,530用于普通字符分配

  • 码位的最大值为10FFFF,对应的二进制有21位(1 0000 1111 1111 1111 1111),刚好以 2 16 2^{16} 216可以分为17个层面

  • 其中第0个层面已经包含了世界上所有用到的字符,其他层面一些表示一些远古时期的文字,还有一些用于留作扩展,目前的Unicode字符集中尚有大量字符空间未使用。

平面编号码位范围(十六进制)名称简写名称
Plane 00000–FFFFBMP基础多语言平面(Basic Multilingual Plane)
Plane 110000–1FFFFSMP补充多语言平面(Supplementary Multilingual Plane)
Plane 220000–2FFFFSIP补充表意语言平面(Supplementary Ideographic Plane)
Plane 330000–3FFFFTIP第三表意语言平面(Tertiary Ideographic Plane)
Planes 4–1340000–DFFFF- (未分配)- (未分配)
Plane 14E0000–EFFFFSSP补充特殊用途平面(Supplementary Special-purpose Plane)
Planes 15–16F0000–10FFFFSPUA-A/B补充私有使用区平面(Supplementary Private Use Area planes)

什么是私有平面?用于给个人做编码扩展,Unicode不指定字符编码,例如游戏中的一个字符代表一种操作,就是用的私有平面 。

上述的是以平面进行分类,在Unicode中还有一个概念:在逻辑上属于一类的字符称为Block

block码位范围(十六进制)类型
C0 Controls and Basic Latin\x0000-\x007FASCII码的128个字符
CJK Unified Ideographs\x4E00-\x9FFC包含大部分的中日韩文字
Halfwidth and Fullwidth Forms\xFF00-\xFFEF用于英文字母/数字/日文/个别符号等一些字符的全角-半角相互转换
Miscellaneous Symbols and Pictographs\x1F300-\x1F5FF包含大部分emoji表情
Supplemental Symbols and Pictographs\x1F900-\x1F9FF包含大部分emoji表情
General Punctuation\x2000-\x206F包含一些符号以及一些特殊的分隔符、连接符、空格符等

编码系统的变化

在Unicode出现之前,所有的字符集都是和具体的编码方案绑定的(字符集≈编码方式),这样的方式通常只需要简单的查表就可以实现。
在这里插入图片描述

Unicode在最初是无法使用的,是一个十六进制的,计算机只能识别二进制数据

怎么才能区分Unicode和ASCII

计算机怎么才知道两个字节表示一个字符,而不是分别表示两个符号呢

如果使用GBK这种双字节编码方式,最高位用0或1表示一个字节或两个字节,就会少了很多值无法表示

这样就诞生了UTF-8、UTF-16、UTF-32

UTF-8

UTF-8是一种变长的编码方式,码位大于\xFFFF的字符,使用4字节存储,小于等于\xFFFF大于\x07FF的使用3字节,小于等于\x07FF大于\x007F的使用2字节,小于等于\x007F使用1字节。

UTF-8直接兼容ASCII码

在UTF8中,

  • 如果字节序列以0开头,代表当前字节本身表示了一个字符。

  • 如果为10开头,则代表当前字节为多字节字符中的一个字节。

  • 如果当前字符以11开头,则前面1的个数,代表当前字符所使用的字节数,2个1代表使用两个字节表示一个字符,3个1代表使用3个字节表示一个字符。

范围码位(二进制)第1个字节第2个字节第3个字节第4个字节
\x0000 … \x007F(7位)00000000 0xxxxxxx0xxxxxxx---
\x0080 … \x07FF(11位)00000yyy yyxxxxxx110yyyyy10xxxxxx--
\x0800 … \xFFFFzzzzyyyy yyxxxxxx1110zzzz10yyyyyy10xxxxxx-
\x10000 … \x10FFFF000uuuuu zzzzyyyy yyxxxxxx11110uuu10uuzzzz10yyyyyy10xxxxxx

UTF-16

变长编码格式,按平面区分,位于第一平面中的字符(\x0000\xD7FF\xE000\xFFFF),使用16位(2字节)存储,使用和码位相同的值。位于其他平面的字符(\x10000\x10FFFF),通过高位和低位代理使用32位(4字节)表示。

UTF-32

是一种定长编码格式,使用32位(4字节)表示Unicode中的一个码位。由于Unicode的码位实际只用了21位,所以多余部分前导0。例如字符小写字母a,对应码位为\x61,存储的字节序列为:\x00000061

因为各个系统之间的字节顺序不同,所以在传输和交换Unicode文本时,要告诉对方当前是以什么顺序保存的,从而接收方才能有效的进行解析。

字节序列标记(Byte order mark,简写BOM),特指\xFEFF字符。在文本的开头,添加\xFEFF字符,用于标识当前文本的字节顺序。

  • 对于UTF8编码格式,该字符会被保存为\xEFBBBF

  • 对于UTF16 BE编码格式,该字符会被保存为\xFEFF

  • 对于UTF16 LE编码格式,该字符会被保存为\xFFFE

  • 对于UTF32 BE编码格式,该字符会被保存为\x0000FEFF

  • 对于UTF32 LE编码格式,该字符会被保存为\xFFFE0000

解析程序通过判断BOM即可确定接下来的文本所使用的编码格式以及字节顺序

当使用UTF8格式保存文本时,Unicode标准建议,如果原文本没有BOM,则不要添加BOM。因为:

  1. UTF8是单字节存储的,不存在字节顺序问题。

  2. 解析器会默认使用UTF8解析文本。

  3. 因为ASCII和UTF8是一一对应的,如果不添加BOM,则ASCII和Unicode可以相互兼容,如果加上了BOM,就打破了相互兼容。

  4. 而对于UTF16和UTF32,要添加BOM,不然在解析的出的文本可能就是乱码,因为解析器在对字节顺序的推算上,并不能保证完全可靠。

BOM可以省略,不是必须的,因为:

  1. 在某些场景下已经预设了编码格式或字节顺序,例如W3C的HTML5规范中,如果指定charset为utf-8,则会默认按照utf-8解析,而如果文件流指定了BOM,则会优先使用BOM指定的编码格式和字节顺序。

  2. 当BOM被省略时,大部分解析器都会对文本流进行推算,推算出编码格式和字节顺序,但是这个推算并不是绝对可靠的。


字节顺序标记(Byte order mark),指预定义的,放置在文本流开头的,一段特殊的字节序列,用于标记当前文本使用的哪种编码格式(UTF32/UTF16/UTF8)。具体规则如下:

编码格式文本流开头的字节序列
UTF-8EF BB BF
UTF-16 (BE)FE FF
UTF-16 (LE)FF FE
UTF-32 (BE)00 00 FE FF
UTF-32 (LE)FF FE 00 00

例如Windows的记事本应用,将文本保存为UTF8格式时,会在文本内容的开头添加\xEF,\xBB,\BF3个字节。记事本应用在读取一个文本文件的时候,发现前三个字节为\xEF,\xBB,\BF,则认为接下来的字节流通过UTF8形式解析。

字节顺序(endianness),这里特指当保存一个数字类型数据时,存储的字节序列的顺序。分为大端序(big-endian,简写BE)和小端序(little-endian,简写LE)。

假设当前要将一个16位的整型数字\x0A0B指向内存地址\x100。

对于大端序的CPU,随着内存地址的增加,认为其存储的值的重要性是递减的,所以大端序的CPU会在\x100的位置上存储\x0A,在\x101的位置上存储\x0B

对于小端序的CPU,随着内存地址的增加,认为其存储的值的重要性是递增的,所以小端序的CPU会在\x100的位置上存储\x0B,在\x101的位置上存储\x0A

所以反过来,假设现在在内存中,地址\x100的地方存储了\xAA,在\x101的地方存储了\xBB,假设有一个int16变量指向\x100,对于大端序CPU会认为该变量的值为\xAABB,对于小端序CPU会认为该变量的值为\xBBAA

常见的字符编码方式

常见 CharSet 有:GBK、GB2312、US-ASCII、ISO-8859-1、UTF-8、UTF-16BE、UTF-16LE、UTF-16

编码系统从计算机到文本文件的处理方式

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Carl·杰尼龟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值