流畅的 Python 读书笔记(三)

书中的数据结构还差文本和字节序列那一章未阅读完。Python 的 str 是 unicode 类型,编码在应用方面基本上就是 .decode(), .encode() 方法的调用,默认编解码时用 UTF-8 就行,差不多就不用太深入了。

Python 的 bytes 和 bytearray 中的元素都是介于 0 ~ 255(含) 之间的整数,即一个字节,bytes 的切片是 bytes, bytearray 的切片还是 bytearray。bytes 和 bytearray 的输出(__repl__) 

  1. 可打印的 ASCII 码以 ASCII 字符贵
  2. 特殊字转义,如 \r, \n, \r, 和 \\
  3. 其他字符以十六进制转义输出,如 \xc3

像 endswith, replace, strip, translate, upper 等函数可以直接用来处理 bytes,如

re 正则表达式模块也能处理二进制序列

bytes/bytearray 与 16 进制之间的转换

bytes 和 bytearray 很多时候可通用。

memoryview + struct 解析字节数据的用法

但为什么要用 memoryview 呢,直接读取 10 个字节就行了

顺便学习下 struct 的用法。

Python 自带超 100 种编码 standard encodings,每个编码有多个名称,如 utf-8, utf8, utf_8, U8 都一样,在 codec 中定义了很多 xxx_encode, xxx_decode 函数。

bytes 与 str 之间的转换,有不兼容的字符时可能抛出 UnicodeEncodeError 和 UnicodeDecodeError 异常,编解码时可指定如何处理错误

a_bytes.encode('cp437', errors='ignore')  # 还可选 errors='replace', errors='xmlcharrefreplace'.

不同字符集间转换也会产生奇怪的字符(鬼符 gremlin 或 mojibake),如 \xe9 在 KOI8-R 是 И, 在 latin1 中是 é, 如果被字符的超集处理都没问题。经常看到被 replace 错误处理时,无法正常处理全用 �(码位是U+FFFD) 表示,还记得那时候的 烫烫烫屯屯屯 吗?恰好对应到 GB2312 的 \xcc\xcc(未初始化的栈内存)和 \xcd\xcd(未初始化的堆内存)。

如果 Python 源码文件使用的编码无法被解释就会报出 SyntaxError: Non-UTF-8 code 这样的错误,解决的办法就是用 utf-8, 或者文件头加上

字符集侦测包 Chardet 可帮助我们找到某个文件使用了什么编码,它支持 30 种编码,用 pip 安装,使用命令 chardetect filename

BOM: 字节序标记(byte-order mark),指示文件编码用的小字节序还是大字节序,UTF-16 可能会在文本前加上这个标记 \xff\xfe 为小字节序,没有 BOM 就假定用大字节序。Intel x86 用的小字节序,很多文件即使不带 BOM 也用小字节序。UTF-16 有两个变种,UTF-16LE(little end) 和 UTF-16BE(big end), 如果直接指定变种名就不需要 BOM。

多字节的字符集,像 UTF-16, UTF-32 才有字节序的问题,像 UTF-8 没有字节序的考虑,不用 BOM。但 Windows 也可能给 UTF-8 加上 BOM 来确定是不是 UTF-8, 像 \xef\xbb\xbf, Python 不认它们。

Python 处理文本的是佳实践是:尽早把字节转换成字符串,程序中尽量处理字符串,尽量晚的把字符串编码成字节序列. -- 俗称 Unicode 三明治

Python 选用何种编码,有不同的状态

  1. 打开文件时由 locale.getpreferredencode() 确定
  2. stdout/stdin/stderr 用 PYTHONIOENCODING 环境变量设置,没有则继承自控制台
  3. 标准输入输出重定到文件用 locale.getpreferedencode() 确定
  4. bytes 与 str 间转换用 sys.getdefaultencoding() 获得编码,在 GNU Linux 和 OSX 中是 UTF-8
  5. 文件名的编解码用 sys.getfilesystemencoding() 确定,比如 open() 打开文件,在 GNU Linux 和 OSX 中是 UTF-8

Unicode 涉及到文本的规范化,如利于搜索,比较。如 ½ 也要能用 1/2 搜索出来,规范化用到 NFC, NFD, NFKC, NFKD 等。Unicode 在不同区域会有不同的排序,非 ASCII 文本排序可能要用到的函数是 local.strxfrm()。

Unicode 数据库,如标示每一个字符的 isprintable(), isnumeric(), isdecimal() 等,比如 

上面那些都是 isnumeric()

Python 的 re 模块对 Unicode 支持不充分,可用 PyPI 的 regex 模块。re 应用于字节序列,\d, \w 只能匹配 ASCII 字符,字符串模式,\d 还能匹配到 \u3285 那样不同语言中的数字。

就让本文全是关于字符集的内容,后面开始 Python 编程方面的特性了 -- 函数。

本文链接 https://yanbin.blog/fluent-python-reading-notes-3/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments