计算机的编码问题

文章内容只是个人认识,用于整理和日后回忆。

编码

​ 计算机出现之后,输入问题就一直随着计算机的普及和传播而扩展。从一开始的ascii就可以支持全部内容,到各国语言的输入,然后是统一规范的出现。

基本概念

​ 其实关于字符集和编码方式,总是很容易叫混,查资料时经常遇到教的不一样的。我选择了一种自我感觉比较合理的叫法。?

字节: 字节是计算机存储数据的基本单位。都知道数据的表示是用位(bit)。1字节=8bits

字符: 针对不同编码方式有不同的大小,通常都是n个字节。

字节序: 在字符存储到计算机中时,对于超过一个字节的字符的字节排序方式。

BOM: Byte Order Mark,字节序表示,utf-16和utf-32前必须表明,utf-8正规是没有的,但是也给了一种格式,就是带BOM的utf-8,就是在文件内容最前面加上BOM。

字符集: 人类识别的字符与定义的数字对应的集合。比如:ANSI、Unicode

代码页: 表示不同的ANSI集合。与Unicode只维护一个集合不同,ANSI集合众多,每个集合都是一个代码页。可以在Windows中选择不同代码页来选择你使用的语言。

编码方式: 字符集的实现。不同实现采用不同的数据结构来存储对应的数字。相同字符集的编码方式,针对同一字符时,存储的数字是一致的。比如:gb2312utf-8

字节序–大端小端

​ 据说大端小端的起源是《格列佛游记》:Lilliput和Blefuscu这两个强国在过去的36个月中一直在苦战。战争的原因:大家都知道,吃鸡蛋的时候,原始的方法是打破鸡蛋较大的一端(big endian),可以那时的皇帝的祖父由于小时侯吃鸡蛋,按这种方法把手指弄破了,因此他的父亲,就下令,命令所有的子民吃鸡蛋的时候,必须先打破鸡蛋较小的一端(little endian),违令者重罚。然后老百姓对此法令极为反感,期间发生了多次叛乱,其中一个皇帝因此送命,另一个丢了王位,产生叛乱的原因就是另一个国家Blefuscu的国王大臣煽动起来的,叛乱平息后,就逃到这个帝国避难。据估计,先后几次有11000余人情愿死也不肯去打破鸡蛋较小的端吃鸡蛋。

​ 虽然故事中的大端小端和机器中的大端小端并没有生么相似性,但是还是采用了使用了他们的名字,而且使用至今?。如果不能处理好,不同系统之间的字节序问题,也会造成故事中那样严重的后果。交互的数据会一塌糊涂。

区别

​ 字节序就是数据存储的顺序。并不是所有的数据都是8bit,比如c语言中的int、long等数据类型。所以,对于超过了8bit的数据,有着存储方式的差异。即低地址存储数据高位还是地位,也就是大端小端的区别。

​ 举一个例子,一个32bit的数据:0x123412就是数据的高位,34就是数据的地位。存储地址假设从0x1000开始。

地址大端数据小端数据
低位0x10001234
高位0x10013412
特点

大端模式:符号位固定在第一个字节,容易判断正负。

小段模式:强制转换不需要调整字节内容。

常见的字节序

cpu的字节序
  • cpu的架构
    • x86
    • PowerPC
    • ARM

​ cpu的架构其实就是规定了cpu操作的指令集。其中以x86为势头最猛,他是有Intel推出的兼容8bit、16bit以及32bit的cpu架构。但是现在,随着cpu的发展,32bit已经远远满足不了需求,相应的发展已经不完全受Intel控制。x86架构后的64bit,也面临着需要兼容低版本等等问题。这些不在这里讨论。

​ 每个品牌的计算机使用不同的架构。首先是架构的推出:

架构研发公司公司
x86Intel
PowerPCIBM、Apple和Motorola
ARMARM

​ 然后是部分主流产品的使用:

使用公司架构
Intelx86
AMDx86
苹果前期PowerPC,05年以后x86
ARMARM
IBMPowerPC
  • 架构对应的字节序:
架构字节序
x86小端模式
PowerPC打断模式
ARM硬件选择,两种都可以,默认是小端

语言的字节序

语言字节序
c跟随系统
Java大端模式

​ 这里需要注意,Java的运行相当于是自己开了一个虚拟机,所以可以做到全平台运行。他包装了底层cpu的指令,采用大端模式。

​ 这里就可以回顾一下开头的大小端问题。如果有两个系统,一个是c语言程序,一个是Java语言程序,而c又是在Intel或者AMD的cpu上(显然大部分情况都是这样的)。如果直接交换数据,那么数据就跑偏了。

网络协议的字节序

​ 为了统一,默认就是大端模式

字符集

​ 我所知道的字符集也就是ANSI和Unicode这两种了。还有查资料时遇到的EBCDIC,过于古老,丢弃。

​ ANSI与Unicode的分割是很明显的。ANSI有着众多不同定义,基本每种语言都有不下一种,为此还诞生了代码页这一特殊概念。Unicode则是以强势之姿包揽了所有字符,全部放在了一个集合里。

ASCII

​ ASCII码可以说是计算机的起源编码,沿用至今,而且还被几乎所有的编码方式兼容,地位不可谓不高。所以单独拎出以示尊敬。

​ ASCII码以128个代码位表示了起初电脑的所有符号和操作位。其中前33个和最后1个都是控制符(0-32)、后面的则表示各种可见符号。在早期,计算机只在美国等国家传播时,ASCII码就足以支撑全部操作了。但是随后,计算机走向世界,需要各种语言的符合加入,ASCII就不太够用了。

ASCII值控制字符ASCII值控制字符ASCII值控制字符ASCII值控制字符
0NUT32(space)64@96
1SOH33!65A97a
2STX34"66B98b
3ETX35#67C99c
4EOT36$68D100d
5ENQ37%69E101e
6ACK38&70F102f
7BEL39,71G103g
8BS40(72H104h
9HT41)73I105i
10LF42*74J106j
11VT43+75K107k
12FF44,76L108l
13CR45-77M109m
14SO46.78N110n
15SI47/79O111o
16DLE48080P112p
17DCI49181Q113q
18DC250282R114r
19DC351383S115s
20DC452484T116t
21NAK53585U117u
22SYN54686V118v
23TB55787W119w
24CAN56888X120x
25EM57989Y121y
26SUB58:90Z122z
27ESC59;91[123{
28FS60<92/124|
29GS61=93]125}
30RS62>94^126`
31US63?95_127DEL

ANSI

​ ANSI出现早于Unicode,而且没有美国因为个别原因的阻挠,使用效果应该是比Unicode家族的要风光的多。那个个别原因在Unicode在下一节吐槽。

​ ASCII码显然只用了一半,全部用在了首位为0的代码位上。后面还有空余的怎么版,还有这么多其他语言的符号没有加入,怎么可以浪费!

​ ANSI是在计算机传播时,针对8bit的剩余空间研发的各个语言的版本。当时没有统一组织出面制定规则,所以出现了百花齐放的情况。基本形成了一种语言一种集合,甚至是多种集合。当然,他们都是想办法利用127号之后的位置,没有改动前面的。而对于像汉语这种规模庞大的字符集,更是采取了双字节表示。 不过紧接着问题出现了,每种集合都占用了相同的位置,位置该归谁呢?

​ 由此出现了代码页的概念。系统依据居住地自动给选择对应的代码页,采用相对应的字符集合。这里集合与编码方式是一一对应的。如gb2312即表示简体中文的所有集合,也代表着编码方式。

​ 简单列举几个:

编码应用
iso-8859-1部分欧洲语言
gb2312简体中文
big-5繁体中文
gbk简体中文和繁体中文
gb18030少数民族文字、简体中文和繁体中文
utf-8世界各国的语言

Unicode

​ Unicode的出现可以说是必然的,因为总不能每次国际交易都要来回的转换编码方式,那也太麻烦了。于是Unicode出现了,他收集了地球上所有语言符号,以及一些其他符号。而且让然选择了将ASCII码的地位放在最前面。因为符号之多,采用了两个字节才能完全表示,这也是Unicode的第一个版本ucs-2。ucs-2的概念显然比较通俗易懂,就是说用两个字节表示符号。

​ 平静一段时间后,美国不满足了,他们的字符全部在前面,所以使用时每个字符都固定有一个字节全为0,他们不爽,就不能直接使用Unicode作为编码方式。原本字符集与编码方式统一的格局也被迫改变了,Unicode只作为字符集,而不再表示编码方式。也因此诞生了utf-8。

​ Unicode目前有两个主要版本:ucs-2、ucs-4。ucs-2使用2个字节,ucs-4使用4个字节、而且ucs-4也是沿用ucs-2的代码位,外加了一些平面辅助的符号。ucs-4只用到了21个字符,不过考虑到以后的发展和方便还是使用了4个字节。目前来说,ucs-4一般还是用不到的。

​ Unicode目前有4种使用编码方式,如:utf-8、utf-16和utf-32。由于历史遗留问题,Unicode的编码方式也被放入了代码页中,不过显然,这个种类就少了很多。

​ utf-7严格来说并非unicode认定的实现方式之一。只是曾为实现邮件发送而提出将unicode转换为US-ASCII的一种方式。曾经的邮件发送并不支持非ASCII码的传输。

​ Unicode的出现所示真正的解决了国际化问题,目前主流的计算机中的cpu处理数据时,包括Java模拟的虚拟机,都是将硬盘中的数据翻译成Unicode再加载到内存中的。保存时,再翻译成对应的数据放回。

编码方式

​ 编码方式的种类实在是太多了,只讲几个常用的。前面讲过的ASCII码就不再罗嗦了。

中文

​ 中文的编码方式主要有四种。最出版的gb2312,由中国国家标准总局1980年房补,只包含简体中文;然后是big-5,由台湾财团法人信息产业策进会为五大中文套装软件(并因此得名Big-5)所设计的中文共通内码,在1983年12月完成公告,用于繁体字;GB13000在Unicode1.1发布同年发布,但是一直未被业界采用;gbk,微软利用了GB2312中未使用的编码空间,并且收录了GB13000中的全部字符,从而定制了GBK编码(虽然收录了GB13000的全部字符,但是编码方式并不相同);gb18030,也是中国正式发布的,包含了部分少数民族语言,简体中文、繁体中文,还有日韩所有文字。

​ 中文的编码都是至少两个字节的,字节序都是采用大端模式。这些编码方式其实都不涉及字节序,不想utf-16还分成utf-16BE和utf-16LE两种编码方式。

gb2312

​ 比较重要的中文编码方式,中内地比较常用。表示英文一个字节,表示中文两个字节。

gbk

​ 也是比较常用的编码方式,基于gb2312扩展,完美兼容。表示英文一个字节,表示中文两个字节。

gb18030

​ 该编码方式不定。分为1、2和4字节三种。

通用

​ 通用的编码格式不多,各有好处。不过个人觉得utf-16LE应该是最理想的,但是使用最多的必然还是utf-8。

utf-8

​ UTF-8编码规则:如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的字节数,其余各字节均以10开头。UTF-8转换表表示如下:

Unicode/UCS-4bit数UTF-8byte数备注
0000 ~007F0~70XXX XXXX1
0080 ~07FF8~11110X XXXX10XX XXXX2
0800 ~FFFF12~161110XXXX10XX XXXX10XX XXXX3基本定义范围:0~FFFF
1 0000 ~1F FFFF17~211111 0XXX10XX XXXX10XX XXXX10XX XXXX4Unicode6.1定义范围:0~10 FFFF
20 0000 ~3FF FFFF22~261111 10XX10XX XXXX10XX XXXX10XX XXXX10XX XXXX5说明:此非unicode编码范围,属于UCS-4 编码早期的规范UTF-8可以到达6字节序列,可以覆盖到31位元(通用字符集原来的极限)。尽管如此,2003年11月UTF-8 被 RFC 3629 重新规范,只能使用原来Unicode定义的区域, U+0000到U+10FFFF。根据规范,这些字节值将无法出现在合法 UTF-8序列中
400 0000 ~7FFF FFFF27~311111 110X10XX XXXX10XX XXXX10XX XXXX10XX XXXX10XX XXXX6

​ utf-8其实本身是只有一种格式的,而且是大端模式。但是由于utf-16和utf-32有两种,莫名的给utf-8也加了一种。叫做带BOM的utf-8,字节序还是大端模式,但是在文件开头加上了FE FF,就是大端模式的标记。

utf-16

分为两种:

  1. utf-16LE
  2. utf-16BE
utf-16LE

​ 采用小端模式,文件开头有FF FE的标识。

utf16-BE

​ 采用大端模式,文件开头有FE FF的标识。这个其实可以理解为Unicode的ucs-2完全复制。编码格式与符号位完全对应。

utf-32

​ 基本与utf-16一样,不过对应的是ucs-4。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值