目录
一、ASCII码
计算机内部,所有信息最终都是一个二进制值。每一个二进制位(bit)有`0`和`1`两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从`00000000`到`11111111`。
上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为 ASCII 码,一直沿用至今。
ASCII 码一共规定了128个字符的编码,比如空格`SPACE`是32(二进制`00100000`),大写的字母`A`是65(二进制`01000001`)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的一位统一规定为`0`。
#ord()获取字符的整数表示(ascii码/unicode数值),chr()函数将编码转化为对应的字符
>>> ord('a')
97
>>> ord('#')
35
import sys
print(sys.getdefaultencoding())
""" 获得系统的默认编码 """
string = input("请输入一个中文字符:")
#严
print(type(string))
print(string + '的ascii编码为:', ord(string))
""" 20005 """
#hex为16进制编码
print(string + '的hex编码为:', hex(ord(string)))
""" 0x4e25 """
ASCII码对照表如下:
二、 Unicode编码
要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。
可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是 Unicode,就像它的名字都表示的,这是一种所有符号的编码。
Unicode 当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,`U+0639`表示阿拉伯字母`Ain`,`U+0041`表示英语的大写字母`A`,`U+4E25`表示汉字`严`。
具体的符号可以查询 [unicode.org]:https://www.unicode.org/
汉字对应表:http://www.chi2ko.com/tool/CJK.htm
需要注意的是,Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。
比如,汉字`严`的 Unicode 是十六进制数`4E25`,转换成二进制数足足有15位(`100111000100101`),也就是说,这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。
这里就有两个严重的问题,第一个问题是,如何才能区别 Unicode 和 ASCII ?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果 Unicode 统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是`0`,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。
它们造成的结果是:
- 出现了 Unicode 的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示 Unicode。
- Unicode 在很长一段时间内无法推广,直到互联网的出现。
"""
unicode_escape是对unicode编码的字节流,两个字节两个字节转义,并以十六进制输出
中文的unicode编码是其hex编码的 0x 换成\\u
string-escape是对二进制的字节流,一个字节一个字节转义,并对每个字节以16进制输出
字符的unicode编码是其ascii值前加上 &# (xss攻击中替换字符为unicode值,html为utf-8编码 javascript:alert("xss")-->java$#115cript:alert("xss"))
在 Python3 中,bytes 和 str 的互相转换方式是
str.encode(‘utf-8’)
bytes.decode(‘utf-8’)
"""
三、UTF-8
UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。其他实现方式还包括 UTF-16(字符用两个字节或四个字节表示)和 UTF-32(字符用四个字节表示),不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8 是 Unicode 的实现方式之一。
UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
"""
utf-8的编码规则,字母x表示可以编码的位
1.对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码,因此对于英文字母,UTF-8编码和ASCII码是相同的
2.对于n(n>1)字节的符号,第一个字节的前n位设置为1,第n+1位设为0,后面字节的前两位一律为10.剩下的没有提及的二进制码,均为这个符号的unicode码
下表总结了编码规则
n Unicode符号范围 UTF-8编码方式
(十六进制) (二进制)
1 0000 0000 - 0000 007F (0-128) 0xxxxxxx
2 0000 0000 - 0000 07FF (128-1047) 110xxxxx 10xxxxxx
3 0000 0000 - 0000 FFFF (2048-65535) 1110xxxx 10xxxxxx 10xxxxxx
4 0001 0000 - 0010 FFFF ... 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5 0020 0000 - 03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6 0400 0000 - 7FFF 007F 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
"""
>>> int(0x7F) //0-127
127
>>> int(0xff) //128-2047
255
>>> int(0x7ff) //2048-65535
2047
>>> int (0xffff)
65535
>>> int(0x10ffff)
1114111
跟据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是`0`,则这个字节单独就是一个字符;如果第一位是`1`,则连续有多少个`1`,就表示当前字符占用多少个字节。
下面,还是以汉字`严`为例,演示如何实现 UTF-8 编码。
#第一步:先求出严的ascii码
>>> ord('严')
20005
#第二步:将ascii码转为二进制,有16位,根据上面的规则,发现在第三个组里面,占三个字节
>>> bin(20005)
'0b 100 111000 100101'
#第三步:占三个字节,所以它的编码格式为:
'1110xxxx 10xxxxxx 10xxxxxx'
#第四步:从'严'的最后一个二进制位开始,依次从后向前填入格式中的'xx',多出的位补0,得到UTF-8编码
'11100100 10111000 10100101'
#转成16进制就是
'E4B8A5'
严的utf-8编码为: b'\xe4\xb8\xa5'
四、URL编码
字母不需要进行url编码,字母的url编码还是原来的字母
特殊字符(例如@、#等)的url编码是其ASCII值的16进制,前面加个%,这个在注入中常用
from urllib.parse import quote
from urllib.parse import unquote
string1 = input('请输入一个字符:')
print(string1 + '的url编码为:', quote(string1, 'utf-8'))#将字符进行utf-8编码
"""
请输入一个字符:@
@的url编码为: %40
"""
中文的 url 编码是其 utf-8 编码前面加个 %
from urllib.parse import quote
from urllib.parse import unquote
string1 = input('请输入一个字符:')
print(string1 + '的utf-8编码为:', string1.encode('utf-8'))
print(string1 + '的url编码为:', quote(string1, 'utf-8'))#将字符进行utf-8编码
string2 = input('请输入一个url编码:')
print(string2 + '对应的字符为:', unquote(string2, 'utf-8'))#将url编码转换为字符
"""
严的utf-8编码为: b'\xe4\xb8\xa5'
严的url编码为: %E4%B8%A5
请输入一个url编码:%E4%B8%A5
%E4%B8%A5对应的字符为: 严
urlencode编码最后一步,需要将前面转换好的utf-8编码,分别进行16进制的转换,然后在每个字节前面加上%
"""
五、base64编码
"""
在 Python3 中,bytes 和 str 的互相转换方式是
str.encode(‘utf-8’)
bytes.decode(‘utf-8’)
=python中的encode,decode方法=
首先,要知道encode是 unicode转换成str。decode是str转换成unicode。
下文中,u代表unicode类型的变量,s代表str类型的变量。
u.encode('...')基本上总是能成功的,只要你填写了正确的编码。就像任何文件都可以压缩成zip文件。
s.decode('...')经常是会出错的,因为str是什么“编码”取决于上下文,当你解码的时候需要确保s是用什么编码的。就像,打开zip文件的时候,你要确保它确实是zip文件,而不仅仅是伪造了扩展名的zip文件。
u.decode(),s.encode()不建议使用,s.encode相当于s.decode().encode()首先用默认编码(一般是ascii)转换成unicode在进行encode。
"""
下面代码里面,由于base64这个只接受bytes类型变量,所以字符在encode之前先要转换为bytes类型,所以会有s.encode('utf-8')这句,之后再decode。
import base64
"""
不要命名为base64
"""
s = input("请输入一个字符:")
bs = base64.b64encode(s.encode('utf-8')).decode('utf-8')
print(bs)
string2 = input("请输入一个base64编码:")
print(string2 + "对应字符为:", base64.b64decode(string2.encode('utf-8')).decode('utf-8'))
"""
请输入一个字符:你好
5L2g5aW9
请输入一个base64编码:5L2g5aW9
5L2g5aW9对应字符为: 你好
"""
六、附
mport sys
print(sys.getdefaultencoding())
""" 获得系统的默认编码 """
string = input("请输入一个中文字符:")
#严
print(type(string))
print(string + '的ascii编码为:', ord(string))
""" 20005 """
print(string + '的hex编码为:', hex(ord(string)))
""" 0x4e25 """
print(string + '的unicode编码为:', string.encode('unicode_escape'))
""" b'\\u4e25' """
print(string + '的utf-8编码为:', string.encode('utf-8'))
""" b'\xe4\xb8\xa5' """
print(string + '的utf-16编码为:', string.encode('utf-16'))
""" b'\xff\xfe%N' """
print(string + '的gbk编码为:', string.encode('gbk'))
""" b'\xd1\xcf """
print(string + '的gb2312编码为:', string.encode('gb2312'))
""" b'\xd1\xcf """
print(string + 'utf-8_gbk编码:', string.encode('utf-8').decode('utf-8').encode('gbk'))
"""编码解码方式错误会导致乱码"""
print(string.encode('utf-8').decode('unicode_escape'))
""" 严 """
a = '\u674e\u83f2\u83f2'
print(a.encode('utf-8').decode('utf-8'))
print(a.encode('utf-8'))