跳转至

Encode

编码(encode)就是将各种形式的输入根据一定的编码系统转换为数字(码点),然后再将各种进制的数字转换为计算机可以识别的二进制

二进制数字(binary digit)简称 bit(比特,或者叫位),即 0 或 1,8 位称作 1 个字节

计算机诞生美国,最初只考虑到26个基本拉丁字母的大小写、阿拉伯数字和英式标点符号等现代英语环境的一些元素(即键盘上那些东西),使用128个整数即可完整表示,于是诞生了ASCII编码系统。

ASCII 字符表前32个字符都是控制字符,很多都源于遥远的电报时代
比如,当电传打字机打印完一行之后,需要用一个控制命令把打印头复位回打印纸的左边,然后再用另一个控制命令把打印头往下移动一行
这俩动作分别对应了两个控制字符(CR & LF),也就是所谓的回车和换行

后来计算机传入西欧,他们所特有的字符无法完全用ASCII表示,于是做了扩展(表格符号,计算符号,希腊字母,拉丁符号),统称EASCII

无论ASCII还是EASCII,使用8bit(1Byte)二进制即可表示,所以都属于单字节系统。

但是汉字有成千上万个,即使常用的也有2500个,所以至少需要两个字节来表示,于是中国在ASCII的基础上制定了GB2312编码(包含6763个汉字),后来又在此基础上创建了GBK(27484个汉字,同时还包含藏文蒙文维吾尔文等少数民族文字),除了中国外,还有其他国家也会存在这样的问题,比如日文,韩文等,每个国家都制定一套自己标准,不可避免的会出现冲突。

于是人们就想着把所有语言统一到一套编码中,当时做这件事的有两个团队,一个叫UCS,一个叫Unicode,当他们发现对方的存在时决定共同搞一套规范,名字就叫Unicode,俗称万国码/统一码。它也是兼容ASCII的。通常用U+xxx形式表示。需要被定义的符合有很多,所以它肯定不是一次性定义完的,比如7.0版本时已收录了10w+符号,那它是咋定义的呢:分区,每个区可以存放2的16次方个字符,被称为一个平面,目前共有17分区/平面。最先被定义的肯定是最常见的那些字符,它们被放在了第一个分区/平面,称作基本平面(缩写为BMP,从U+0000到U+FFFF)剩下的都叫辅助平面(SMP)

Unicode只规定了每个字符对应的码点(数字),而一个码点占用几个字节由Unicode的编码方式UTF规定,也叫字符集,比如UTF-32,规定四个字节表示一个码点,但这出现了一个问题,就是如果文本都是纯英文的话,那么就比直接用ASCII多4倍的存储空间。所以出现了边长型的UTF-8编码,它会根据不同码点大小占用1~6个字节,比如英语通常为1Byte,汉字为3Byte,很节省空间。一般在计算机内存中会统一使用Unicode,但在存储和传输的时候都会转换为UTF-8以节省空间和提高性能。

Python3.x默认使用UTF-8,但像Python2.x等编程语言比 Unicode 诞生要早,所以默认编码是ASCII,所以一般需要在源码开头声明编码格式

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
第一行. 告诉类Unix系统这是一个Python可执行程序,Windows系统会忽略这个注释
第二行. 告诉Python解释器按照UTF-8编码读取源代码,也可以写为:coding=utf-8
"""

另外还有UTF-16,结合了定长和变长的方式。基本平面的字符占用2个字节,辅助平面占用4个,就是说要么占用2个要么4个字节。其实UTF-16是之前的UCS-2的超集,后来取代了UCS-2,因为UCS-2有个问题就是一个字符如果是4字节的会被当成两个2字节的字符,而UTF-16为此做了一个巧妙的设计(辅助平面的字符被拆成了两个基本平面的字符表示)避免了这个问题。

由于JS诞生于(1995年)UCS-2(1990年)和UTF-16(1996年)之间,所以最初选用了USC-2编码方式(没有选用UTF-8是因为当时UTF-8还不成熟,而UCS-2在内存方面操作及使用效率更高),不过ES6已经改为默认UTF-16,不会再有4字节的问题。

进制转换

  • 十进制(Decimal):人类有十个手指头,为了方便理解,通常使用十进制
  • 二进制(Binary):计算机芯片内使用的是门电路,只能表示0和1两个状态,所以使用二进制
  • 十六进制(Hexadecimal):在代码书写时,为了简短显示,一般会使用十六进制,1位16进制是4bit,2位16进制数字是1Bytes
  • 八进制(Octal)

与十进制互转

  • 10进制转任意进制:除基取余,直到商为0,余数倒序
bin(15)  # 转成二进制 0b1111
oct(15)  # 转成八进制 0o17
hex(15)  # 转成十六进制 0xf
  • 任意进制转10进制:系数*基数^权次幂(幂从0开始)
"""
十进制满10进1
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15...
1024 = 1*10^3+0*10^2+2*10^1+4*10^0 = 1*1000+0*100+2*10+4*1 = 1024
数位为: 10^(n-1), ..., 1000, 100, 10, 1

二进制满2进1
0,1,10,11,100,101,110,111...
0b110 = 1*2^2+1*2^1+0*2^0 = 1*4+1*2+0*1 = 6
数位为: 2^(n-1), ..., 8, 4, 2, 1

八进制满8进1
0,1,2,3,4,5,6,7,10,11,12,13,14,15...
0o711 = 7*8^2+1*8^1+1*8^0 = 7*64+1*8+1*1 = 457
数位为: 8^(n-1), ..., 512, 64, 8, 1

十六进制满16进1
0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,10,11...
0xABC = 10*16^2+11*16^1+12*16^0 = 10*256+11*16+12*1 = 2748
数位为: 16^(n-1), ..., 4096, 256, 16, 1
"""

int(0b1111)  # 15
int(0o17)  # 15
int(0xf)  # 15

与二进制互转

  • 2进制与8进制互转:3位一组,421码
oct(0b1101)  # 0o15
bin(0o15)  # 0b1101
  • 2进制与16进制互转:4位一组,8421码
hex(0b1101)  # 0xd
bin(0xd)  # 0b1101

最后更新: 2023-06-01