Python之字符编码汇总

一、常见编码
ASCII:ASCI码是美国标准信息交换码(American Standard Code for Information Interchange)。因为计算机内的所有信息最终都是一个二进制值,每个二进制位(bit)有0和1两种状态,所以8个二进制位可以组合256种状态,称为字节(byte)。ASCII标准 该代码总共规定了128个字符的代码,因为它只使用了后七个字符,而前一个字符统一规定为0。之后,IBM制定了128个扩展字符,不是标准的ASCII代码,而是用来表示框架线、音标和其他欧洲非英语字母。
在英语中使用128个符号代码就足够了,但在其他语言中使用128个符号是不够的。此外,不同的国家使用不同的字母。一些国家使用的字符远远超过256个。显然,ASCII无法解决这个问题。那么,有没有一种统一而唯一的编码方法呢?答案是Unicode。
Unicode:Unicode是计算机科学领域的行业标准,Unicode 它是为了解决传统字符编码方案的局限性而产生的。它为每种语言中的每个字符设置了统一和唯一的二进制编码,以满足跨语言和跨平台文本转换和处理的要求。
但是Unicode也有问题。比如“中”字的Unicode编码是16进制的4E2D,即10011001101101占15位,也就是说这个符号至少需要两个字节,那么你怎么知道这两个字节是一个字符而不是两个字符呢?也就是说,如何区分Unicode和ASCII?
UTF-8:UTF是“Unicode Transformation Format缩写,可翻译成Unicode字符集转换格式。UTF-8 它是互联网上使用最广泛的Unicode实现方法之一,其他实现方法包括UTF-16(两个字节或四个字节表示字符)和UTF-32(四个字节表示字符)。UTF-8的一个特点是它是一种更长的编码方法。它可以使用1~6个字节来表示一个符号,并根据不同的符号改变字节长度。对于UTF-8编码的一个字符,如果只有一个字节,它的最高二进制位置为0;若为多字节,其第一个字节从最高位开始,连续二进制位值为1的个数决定了其编码的位数,其余字节从10开始。
字节数 | UTF-8编码(二进制)
1 | 0xxxxxxxxxx
2 | 110xxxxx 十xxxxxxxx
3 | 1110xxxx 十xxxxxxxx 十xxxxxxxx
4 | 11110xxx 十xxxxxxxx 十xxxxxxxx 十xxxxxxxx
5 | 111110xx 十xxxxxxxx 十xxxxxxxx 十xxxxxxxx 十xxxxxxxx
6 | 1111110x 十xxxxxxxx 十xxxxxxxx 十xxxxxxxx 十xxxxxxxx 十xxxxxxxx
显然,用UTF-8编码“中”字需要三个字节,所以从“中”字的最后一个二进制位开始,从后到前填充格式中的x,多余的位补0。这样就得到了“中”字的UTF-8编码,结果是:1100100 10111000 10101101,即16进制E4B8AD。
相关推荐:Python视频教程
二、Python3编码
Python中的编码问题困扰了我很长一段时间,尤其是Python2和Python3,但这里我只讨论Python3中的编码问题。
Python3最重要的新特性可能是对文本和二进制数据有更清晰的区别。文本总是Unicode,由str类型表示,二进制数据由bytes类型表示,两者之间的转换由编码表示(encode)和解码(decode)实现。以下是Python的官方文件:
str.encode(encoding="utf-8",errors="strict") Returnanencodedversionofthestringasabytesobject.Defaultencodingis'utf-8'.errorsmaybegivento setadifferenterrorhandlingscheme.Thedefaultforerrorsis'strict',meaningthatencodingerrorsraise aUnicodeError.Otherpossiblevaluesare'ignore','replace','xmlcharrefreplace','backslashreplace'andany othernameregisteredviacodecs.register_error(),seesectionErrorHandlers.Foralistofpossibleencodings, seesectionStardardEncodings. bytes.decode(encoding="utf-8",errors="strict") Returnastringdecodedfromthegivenbytes.Defaultencodingis'utf-8'.errorsmaybegiventosetadifferent errorhandlingscheme.Thedefaultforerrorsis'strict',meaningthatencodingerrorsraiseaUnicodeError. Otherpossiblevaluesare'ignore','replace'andanyothernameregisteredviacodecs.register_error(),see sectionErrorHandlers.Foralistofpossibleencodings,seesectionStardardEncodings.
可以看出,str没有decode方法,因为它是Unicode编码,而bytes没有encode方法,无论是encode还是decode默认使用UTF-8编码,当然,我们也可以使用其他方法来编码和解码,例如:
s="博客园"
print(s.encode())
print(s.encode("utf-16"))
print(s.encode("gbk"))
#b'\xe5\x8d\x9a\xe5\xaexa2\xe5\x9b\xad'
#b'\xff\xfeZS\xa2[\xedV'
#b'\xb2\xa9\xbf\xcdxd4\xb0#39;那么,对于某个数据,如果我们不知道它的编码格式呢?chardet模块中的detect方法可用于Python3中:
importchardet
print(chardet.detect(b'\xe5\x8d\x9a\xe5\xaexa2\xe5\x9b\xad'))
print(chardet.detect(b'\xff\xfeZS\xa2[\xedV'))
{'encoding':'utf-8','confidence':0.87625,'language':''}
{'encoding':'UTF-16','confidence':1.0,'language':''}detect方法将返回字典,包括编码方法、检测到的概率和语言信息。可以看出,用chardet检测编码很容易。获得编码后,可以转换为str,便于后续处理。
三、文本编码
首先,新建一个文本文档”test.txt内容为:“博客园Blogs”,然后选择“另存为”,可见默认使用ANSI编码:

那么这个ANSI编码是什么呢?由此产生了GB2312,不同的国家和地区制定了不同的标准、GBK、Big5、Shift_JIS和其他自己的代码标准。这些使用1到4个字节来代表一个字符的各种汉字延伸代码,称为ANSI代码。在简体中文Windows操作系统中,ANSI代表GBK代码。那么,如果我们使用默认的ANSI代码,即GBK代码,在阅读文本时会发生什么呢?
withopen("test.txt",'r')asf:
print(f.read())
#Blogs博客园
withopen("test.txt",'r',encoding="gbk")asf:
print(f.read())
#Blogs博客园
withopen("test.txt",'r',encoding="utf-8")asf:
print(f.read())
UnicodeDecodeError:'utf-8'codeccan'tdecodebyte0xb2inposion:invalidstartbyte可以看出,使用UTF-8编码打开时报错了,因为有无法解码的单词符号。如果我们在保存时使用UTF-8编码呢?
withopen("test.txt",'r')asf:
print(f.read())
#锘垮崥瀹㈠bogs
withopen("test.txt",'r',encoding="gbk")asf:
print(f.read())
#锘垮崥瀹㈠bogs
withopen("test.txt",'r',encoding="utf-8")asf:
print(f.read())
#Blogs博客园很明显,使用GBK编码时会出现乱码,因为编码与解码方式不一致,导致最终出现乱码。
四、URL编码
URL是全球统一的资源定位符号(Uniform Resource Locator),一般来说,URL只能使用英文字母、阿拉伯数字和一些标点符号,而不能使用其他文本和符号,因为网络标准RFC1738做出了规定。这意味着,如果URL中有汉字,则必须在编码后使用。但麻烦的是,RFC1738没有规定具体的编码方法,而是由应用程序(浏览器)决定。
这里我们可以随意打开一个网页,比如百度百科全书的编码,你可以看到浏览器显示的链接没有问题:

复制,然后粘贴出来看看:https://baike.baidu.com/item/%E7%BC%96%E7%A0%81/80092,浏览器自动编码“编码”一词BC%96%E7%A0%81”。这里我们需要知道的是,UTF-8编码为E7BC96,UTF-8编码为E7A081,所以“%E7%”BC%96%E7%A0%81是在每个字节前添加一个“%”,即UTF-8编码用于URL路径。
