文本和字节序列

人使用文本,计算机使用字节序列

1. 大纲:

  1. 字符、码位和字节表述
  2. bytes、bytearray和memoryview等二进制序列的独特特性
  3. 全部Unicode和陈旧字符集的编解码器
  4. 避免和处理编码错误
  5. 处理文本文件的最佳实践
  6. 默认编码的陷阱和标准I/O的问题
  7. 规范化Unicode文本,进行安全的比较
  8. 规范化、大小写折叠和暴力移除音调符号的实用函数
  9. 使用locale模块和PyUCA库正确地排序Unicode文本
  10. Unicode数据库中的字符元数据
  11. 能处理字符串和字节序列的双模式API

2. 字符

从Python3的str对象获取的元素是Unicode字符

  1. str1 = 'café'
  2. #café字符串有4个Unicode字符
  3. print(len(str1))
  4. #使用UTF-8把str编码成bytes对象
  5. byte_str1 = str1.encode('utf-8')
  6. #bytes字面量以b开头
  7. print(byte_str1)
  8. #字节序列有5个字节(在UTF-8中,é的码位编码成两个字节)
  9. print(len(byte_str1))
  10. #使用UTF-8把bytes对象解码成str对象
  11. print(byte_str1.decode('utf-8'))

3. 字节

例子1. bytes和bytearray

  1. #bytes对象可以从str对象使用给定的编码构建
  2. cafe = bytes('café', encoding='UTF-8')
  3. print(cafe)
  4. #各个元素是range(256)内的整数
  5. print(cafe[0])
  6. #这里注意,bytes对象的切片还是bytes对象
  7. print(cafe[:1])
  8. cafe_arr = bytearray(cafe)
  9. #bytearray对象没有字面量句法,而是以bytearray()和字节序列字面量参数的形式显示
  10. print(cafe_arr)
  11. #各个元素是range(256)内的整数
  12. print(cafe_arr[0])
  13. #bytearray对象的切片还是bytearray对象
  14. print(cafe_arr[-1:])

例子2. 可以用str类型的方法去处理二进制序列。但二进制序列独有fromhex方法,它的作用是解析十六进制数字对,构建二进制序列:

  1. print(bytes.fromhex('31 4B CE A9'))

例子3. memoryview类不是用于创建或存储字节序列,而是共享内存,让你访问二进制序列、打包的数组和缓冲中的数据切片,而无需复制字节序列,Python Imaging Library(PIL)就是这么处理图像的。其中PIllow为PIL最活跃的派生库。

4. 处理UnicodeEncodeError,UnicodeDecodeError,SyntaxError

处理UnicodeEncodeError和UnicodeDecodeError在encode()和decode()时用errors参数处理。处理SyntaxError在文件头部添加注释,指出编码。

编解码器(codec, encoder/decoder)

用于在文本和字节之间相互转换。

Python自带超过100多种codec, 如'utf_8','latin_1'。这些名称可以传给open()、str.encode()、bytes.decode()等函数。例如3个编码器可以的到3个不同的字节序列。

例子1. encode和decode时errors的使用

  1. octets = b'Montr\xe9al'
  2. #print(octets.decode('utf_8')
  3. #编码时制定errors='relpace',把无法编码的字符替换成"?",官方上表示未知编码
  4. print(octets.decode('utf_8', errors='replace'))

5. 检测文本的编码

一个Python库Chardet, 还有它的一个命令行工具chardetect。

在命令行里输入chardetect * 可以检测当前目录所有文件的编码

文件以b'\xef\xbb\xbf'开头的,这是BOM(bye-order-mark).

UTF-8的一大优势是不需要BOM,因为生成的字节序列保持一致。但是Windows应用(尤其是NotePad)会在UTF-8编码中添加BOM,Excel会根据有没有BOM确定是不是UTF-8编码。

文件如果以b'\xef\xbb\xbf'开头,则有可能是带有BOM的UTF-8编码。但是Python不会以这样的BOM就认为文件是UTF-8。

6. 处理文本文件

Unicode三明治方法:

  1. 对输入来说,尽早把bytes->str。
  2. 只能处理字符串对象,在其他处理过程中,不要encode或者decode。
  3. 对输出来说,尽晚把str->bytes。

    多数Web框架都是这样做,使用框架时很少接触字节序列。例如Django中,视图应该输出Unicode字符串,Django会负责把响应编码成bytes,而且默认使用UTF-8编码。

在Python3中轻松应用Unicode三明治的建议,因为内置的open函数在读取文件时做必要的解码,以文本模式写入文件时还会做必要的编码,所以my_file.read()和my_file.write(text)方法得到的都是字符串对象。

例子1. 获取编码默认值

  1. import sys, locale
  2. expressions = """
  3. locale.getpreferredencoding()
  4. type(my_file)
  5. my_file.encoding
  6. sys.stdout.isatty()
  7. sys.stdout.encoding
  8. sys.stdin.isatty()
  9. sys.stdin.encoding
  10. sys.stderr.isatty()
  11. sys.stderr.encoding
  12. sys.getdefaultencoding()
  13. sys.getfilesystemencoding()
  14. """
  15. print(expressions)
  16. my_file = open('dummy', 'w')
  17. for expression in expressions.split():
  18. #eval() 函数用来执行一个字符串表达式,并返回表达式的值。
  19. value = eval(expression)
  20. print(expression.rjust(30), '->', repr(value))

7. Unicode规范化字符串

有两种组合方式

例如‘é’和''e\u0301(组合字符),是标准等价物(canonical equivalent),应视作相同的字符。len('café')字节数为4,len('cafe\u0301')字节数为5,但码位序列不同(长度不同),所以s1 == s2为False。

此时需要规范化。解决方案是使用unicodedata.normalize函数提供的Unicode规范化。有NFC、NFD、NFKC、NFKD四种。

用户输入默认的是NFC形式。不过,安全起见,保存文本之前,最好是使用normalize('NFC', user_text)清洗字符串。

NFKC和NFKD在特殊情况下使用,例如搜索和索引,而不能用持久存储,因为这种转换会导致数据损失。NFC和NFD可以放心使用。

例子1. NFC(Normalization Form C)使用最少的码位构成等价字符串

  1. from unicodedata import normalize
  2. s1 = 'café'
  3. s2 = 'cafe\u0301'
  4. print(len(s1), len(s2)) #4 5
  5. print('s1 == s2: ',s1 == s2) #False
  6. #规范化
  7. s3 = normalize('NFC', s1)
  8. s4 = normalize('NFC', s2)
  9. print(len(s3), len(s4)) #4 4
  10. print(s3 == s4) #True

例子2. NFD是组合字符(例如e加上音节变成é)。


  1. from unicodedata import normalize
  2. s1 = 'café'
  3. s2 = 'cafe\u0301'
  4. print(len(s1), len(s2)) #4 5
  5. print('s1 == s2: ',s1 == s2) #False
  6. #规范化
  7. s3 = normalize('NFD', s1)
  8. s4 = normalize('NFD', s2)
  9. print(len(s3), len(s4)) #5 5
  10. print(s3 == s4) #True

Note: str.casefold() 可以把文本变成小写。和str.lower()差不多,具体差别看StackOverFlow的提问和文档。从Python3.4起,两个函数得到不同的只占Unicode命名的字符的0.11%。

例子3. 如果要处理多语言文本,工具箱应该有nfc_equal和fold_equal函数。

  1. #比较规范化Unicode字符串
  2. from unicodedata import normalize
  3. def nfc_equal(str1, str2):
  4. return normalize('NFC', str1) == normalize('NFC', str2)
  5. def fold_equal(str1, str2):
  6. return (normalize('NFC', str1).casefold() ==
  7. normalize('NFC', str2).casefold())

8. 极端规范化:去掉变音符号

例如'á'变成'a'。 在某些情况下会用到这个技术,例如Google搜索。另外,

去掉全部变音符号音符)的函数

  1. def shave_marks(txt):
  2. """Remove all diacritic marks"""
  3. norm_txt = unicodedata.normalize('NFD', txt)
  4. shaved = ''.join(c for c in norm_txt
  5. if not unicodedata.combining(c))
  6. return unicodedata.normalize('NFC', shaved)

9. 支持字符串和字节序列的双模式API

双模式API,即提供的函数能接受字符串或字节序列为参数,然后根据类型进行处理。例如,re和os模块就有这种函数。

  1. import os
  2. print(os.listdir('.'))
  3. print(os.listdir(b'.'))

Fluent_Python_Part2数据结构,04-text-byte,文本和字节序列的更多相关文章

  1. 《流畅的Python》第二部分 数据结构 【序列构成的数组】【字典和集合】【文本和字节序列】

    第二部分 数据结构 第2章 序列构成的数组 内置序列类型 序列类型 序列 特点 容器序列 list.tuple.collections.deque - 能存放不同类型的数据:- 存放的是任意类型的对象 ...

  2. python高级(四)—— 文本和字节序列(编码问题)

    本文主要内容 字符 字节 结构体和内存视图 字符和字节之间的转换——编解码器 BOM鬼符  标准化Unicode字符串 Unicode文本排序 python高级——目录 文中代码均放在github上: ...

  3. Python 文本和字节序列

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica } Python 3 明确区分了人类可读的文本字符串和原始的字节序列.隐式 ...

  4. 流畅的python第四章文本和字节序列学习记录

    字符问题 把码位转化成字节序列的过程是编码,把字节序列转化成码位的过程是解码 把unicode字符串当成人类可读的文本,码位当成机器可读的, 将字节序列编程人类可读是解码,把字符串编码成字节序列是编码 ...

  5. Python的文本和字节序列

    一.字符串的表示和存储 字符串是字符的序列,每个字符都有有一个数字作为标识,同时会有一个将标识转换为存储字节的编码方案: s = 'hello world python' for c in s: pr ...

  6. Python文本和字节序列

    ASCII码 早期人们用8位二进制来编码英文字母(最前面的一位是0) 也就是说,将英文字母和一些常用的字符和这128种二进制0.1串一一对应起来, 比如:大写字母“A”所对应的二进制位“0100000 ...

  7. 压缩文本、字节或者文件的压缩辅助类-GZipHelper

    下面为大家介绍一.NET下辅助公共类GZipHelper,该工具类主要作用是对文本.字符.文件等进行压缩与解压.该类主要使用命名空间:System.IO.Compression下的GZipStream ...

  8. 压缩文本、字节或者文件的压缩辅助类-GZipHelper 欢迎收藏

    压缩文本.字节或者文件的压缩辅助类-GZipHelper 欢迎收藏 下面为大家介绍一.NET下辅助公共类GZipHelper,该工具类主要作用是对文本.字符.文件等进行压缩与解压.该类主要使用命名空间 ...

  9. SQL Text Literals 文本

    Text Literals 文本 Use the text literal notation to specify values whenever string appears in the synt ...

随机推荐

  1. redis本地能访问外网不能访问问题

    1.确认配置文件bind的ip是否正确,一般想要外网能访问,需要填写为0.0.0.0,表示监听任何ip 注意任何人都能访问,一定要开启密码 requirepass 你的密码 2.确认protected ...

  2. 图像变换 - 霍夫线变换(cvHoughLines2)

    霍夫变换是一种在图像中寻找直线.圆及其他简单形状的方法,霍夫线变换是利用Hough变换在二值图像中找到直线. 利用CV_HOUGH_PROBABILISTIC,对应PPHT(累计概率霍夫变换)?这个算 ...

  3. mybatis(六):设计模式 - 组合模式

  4. AcWing 8.二维费用的背包问题

    #include<iostream> #include<algorithm> #include<cstring> using namespace std ; ; i ...

  5. 安装rocky版本:openstack-nova-compute.service 计算节点服务无法启动

    问题描述:进行openstack的rocky版本的安装时,计算节点安装openstack-nova-compute找不到包. 解决办法:本次实验我安装的rocky版本的openstack 先安装cen ...

  6. 【Python】变量命名习惯

    仅供参考,个人习惯

  7. noobSTL-1-配置器-1

    noobSTL-1-配置器-1 1.要点分析 1.1 可能让你困惑的C++语法 组态 即配置. 临时对象 一种无名对象.有时候会刻意地制造临时对象. 静态常量整数成员在class内部直接初始化 con ...

  8. cef源码分析之cefsimple

    下面是cefsimple的入口代码,主要分成两个部分 // Entry point function for all processes. int APIENTRY wWinMain(HINSTANC ...

  9. drf的序列化和反序列化

    序列化器--Serializer 选项参数: max_length 最大长度 min_length 最小长度 allow_blank 是否允许为空 trim_whitespace 是否截断空白字符 m ...

  10. Swagger与OAuth 手动搭建WebApi 操作笔记

    1.创建一个空的Web应用程序 2.通过nuget 安装以下插件清单,有部分会在安装其他插件时候自动安装: 3.安装完Swagger 会生成一个目录App_Start,在这个目录中增加文件ApiCon ...