• 编码格式
  • chardet模块
  • 数据交换格式
  • str与bytes
  • 字符串常量


编码格式

以下编码格式是基于某种字符集,规定了每个字符存储时的二进制值是什么。

  • ASCII码:最基本的字符集,总共有128个字符,用一个字节存储一个字符。
  • 比如字母’A’存储时的二进制值是0100 0001。
  • Unicode(统一码、万国码):给多国语言的字符规定了唯一编号(但并没有规定它们存储时采用什么二进制值)。
  • Unicode编码是4个16进制数,通常加上前缀“U+”或“\u”,写成文本的话就占6个字节。因此Unicode编码并不实用。
  • Unicode可以容纳多种主要语言的字符码,但是表示ASCII码字符时,高字节全为零,浪费了存储空间,比如’A’表示成“U+0041”。
  • UTF-8:一种基于Unicode的编码格式,但更实用。
  • UTF-8的编码长度可变(可用1~6个字节),比如存储ASCII码字符时只用1个字节,存储中文字符时用3个字节,这样比Unicode编号更节省存储空间。
  • 与UTF-8同系列的还有UTF-16、UTF-32。
  • BIG5:一种流行的中文繁体编码格式。
  • GBK:一种流行的中文简体编码格式。
  • GBK是GB2312的超集,字符更多。
  • GBK将中文、英文字符都用2个字节存储。
  • ISO-8859-1:属于单字节编码,只收录了英语、希腊语、阿拉伯语等字符,向下兼容ASCII码。
  • 它用到了单字节的所有编码,因此用ISO-8859-1编码存储其它编码格式的数据时,即使解析乱码,也不会遗漏原数据。

以下编码格式不是基于某种字符集,只是对基于ASCII码的字符串进行加工,从而避免在通信传输时出错。

  • URLencode:将字符串转换成URL格式。
  • 按照RFC 3986规范:只保留数字、英文字母和十一种符号( ~@$&=+,;: /? ),其它字符都转换成百分号 %加两位16进制编码。比如空格要转换成 %20。
  • 通常用urllib模块处理,如下:
>>> from urllib import parse
>>> r = parse.quote("http://www.你好.com")
>>> r
'http%3A//www.%E4%BD%A0%E5%A5%BD.com'		# 输出为str类型
>>> parse.unquote(r)
'http://www.你好.com'
  • Base64:将字符串转换成最多64种字符。
  • 转换原理:每次从原数据中取出3个字节,拆分成4组,每组6个bit。然后在每组之前补上00凑成8个bit,最终得到了4个有64种可能取值的字符。如果原数据末尾不足3个字节,则用1个或2个 = 补齐。
  • 标准的Base64表包含了26个大写字母、26个小写字母、10个数字、2个特殊字符 + / ,主要用于转义非ASCII字符、不可打印的ASCII字符。
  • 通常用base64模块处理,如下:
>>> import base64
>>> b = base64.b64encode('hello'.encode())
>>> b
b'aGVsbG8='	# 从utf-8编码的bytes类型转换成了Base64编码的bytes类型
>>> base64.b64decode(b)
b'hello'	# 从Base64解码成utf-8
  • Quoted-printable(可打印字符引用编码):将字符串转换成只剩可打印字符。
  • 转换原理:将原数据中的每个非可打印字符用两个十六进制数表示,并加上等号 = 作为前缀。另外,每行最多有76个字符,超过该长度则插入 = 作为分行符。比如 “=” 要转换成 “=3D”。
  • 常用于编码邮件内容。
  • 通常用quopri模块处理,如下:
>>> import quopri
>>> quopri.encodestring(b"hello world!==\r\n")
b'hello world!=3D=3D\r\n'
>>> quopri.decodestring(b"hello world!=3D=3D\r\n")
b'hello world!==\r\n'

chardet模块

在读取一个文件的内容之前,如果不确定它的编码方式,可以用 chardet模块推测一下。

  • 其原理是通过比对各种字符集的特征字符来猜测编码格式。如果检测的数据量太少,就容易猜错。
  • 不能处理str对象,因为str已经是按Unicode格式编码了。
  • 例:
>>> chardet.detect(b"Hello, world!")
{'encoding': 'ascii', 'confidence': 1.0, 'language': ''}  # confidence表示可信度,这里是100%
>>> chardet.detect("你".encode("GBK")))
{'encoding': None, 'confidence': 0.0, 'language': None}
>>> chardet.detect("你好".encode("GBK"))
{'encoding': 'TIS-620', 'confidence': 0.3598212120361634, 'language': 'Thai'}
>>> chardet.detect("你好,欢迎来到这里!".encode("GBK"))
{'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'}
# 最好把GB2312也当做GBK编码解码,以防chardet把GBK识别成GB2312。
>>> f=open(path, 'rb')	# 也可以使用chardet直接检测一个文件
>>> chardet.detect(f.read())["encoding"]
'GB2312'

数据交换格式

数据交换格式:不属于编码格式,而属于排版格式,是指对str对象的排版,便于供人阅读或通信传输。

常见的几种如下:

  • CSV:逗号分隔值列表,通常用csv模块处理。
  • xlsx:微软公司的Excel表格的格式,可以用openpyxl模块处理。
  • JSON:原本是JavaScript的对象表示格式,后来发展成为一种独立于语言和平台的文本格式。通常用json模块处理。
  • XML:把每项数据都用一对标签包住,不适合给人阅读。通常用xml模块处理。
  • YAML:比JSON更简单。

str与bytes

Python3中,解释器在运行时,默认把字符串保存成str类型,与外部交流时才转换成bytes类型。

  • str:字符串类型,采用Unicode编码格式,以字符为单位处理字符串。
  • bytes:字节类型,与str的用法相同,但采用实用的编码格式(比如utf-8、ASCII),以字节为单位处理字符串。

str.encode(encoding=‘utf-8’, errors=‘strict’)

  • 功能:对str对象进行编码,返回一个bytes对象。
  • errors='strict’表示采用严格模式,一旦编码出错就抛出异常。
  • 例:
>>> "www.你好.com".encode()
b'www.\xe4\xbd\xa0\xe5\xa5\xbd.com'
  • Python终端中看不到str对象的Unicode编码是什么,可以用以下方法强行显示str对象的Unicode编码。
>>> "www.你好.com".encode("unicode_escape")
b'www.\\u4f60\\u597d.com'	# 该字符串的内容被改变了,不能按正常格式解码
>>> "www.你好.com".encode("unicode_escape").decode("unicode_escape")
'www.你好.com'

bytes.decode(encoding=‘utf-8’, errors=‘strict’)

  • 功能:对bytes对象进行解码,返回一个str对象。
  • 例:
>>> b'www.\xe4\xbd\xa0\xe5\xa5\xbd.com'.decode()
'www.你好.com'

字符串常量

字符串常量的可用前缀:

  • r:声明为raw(原始字符),让反斜杠不发生转义。
>>> print(r"Hello!\n")
Hello!\n
  • b:声明为bytes对象。
>>> b"Hello"
b'Hello'
>>> b"你好"			# 该字符串只能包含ASCII字符,否则不能声明为bytes对象
SyntaxError: bytes can only contain ASCII literal characters.
  • u:声明为Unicode字符。
>>> u"你好"
'你好'
>>> u"\u4f60\u597d"
'你好'
  • ASCII码中的非显示字符可以用一个\x加两个十六进制数表示。
>>> '\v\f\b'
'\x0b\x0c\x08'