# 第四章 文本和字节序列"""内容提要:1.Unicode字符串2.二进制序列3.在二者之间转换使用的编码4.字符/码位/字节表述5.bytes/bytearray/memoryview等二进制序列的独特特性6.全部Unicode和陈旧字符集的编解码器7.避免和处理编码错误8.处理文本文件的最佳实践9.默认编码的陷阱和标准I/O的问题10.规范化Unicode文本,进行安全的比较11.规范化/大小写折叠/暴力移除音调符号的实用函数12.使用locate模块和PyUCA库正确第排序Unicode文本13.Unicode数据库中的字符元数据14.能处理字符串和字节序列的双模式API"""# 4.1 字符问题
"""
字符的标识:即码位,是0~1114111的数字(十进制),在Unicode标准中以4~6个十六进制数字表示
加前缀'U+'如A : U+0041欧元符号: U+20AC高音谱号:U+D11E
字符的表述:取决于具体的编码编码是在码位和字节序列之间转化时使用的算法在utf-8中 A 编码为单个字节\x41utf-16LE中  A 编码为两个字节\x41\x00编码:把码位转换为字节序列解码:把字节序列转换为码位"""# 编码和解码
# s = 'café'
# print(len(s)) # 'café'有4个Unicode字符
# b = s.encode('utf8') # 编码
# print(b) # b'caf\xc3\xa9' byte的字面量以b开头
# print(len(b)) # 字节序列有5个字节(在utf8中é的码位编码成2个字节)
# print(b.decode('utf8'))  # 解码# 4.2 字节概要
"""
字节类型:1.bytes 不可变2.bytearray 可变bytes和bytearray对象的各个元素是介于0~255(含)之间的整数二进制序列的切片始终是同一类型的二进制序列二进制序列的字面量表示:1.可打印的ASCII范围内的字节用ASCII字符表示2.制表符 换行符 回车符和\对应的字节用转义序列表示 \t \n \r \\3.其他字节的值,使用时十六进制转义序列 \x00 表示空字节除了格式化方法(format和format_map)和几个处理Unicode数据的方法casefold isdecimal isdentifier isnumeric isprintable encode外str类型的其他方法都支持bytes和bytearrayre模块也支持处理二进制序列"""# 使用数组中的原始数据初始化bytes对象
# 例 包含5个字节的bytes和bytearray对象"""cafe = bytes('café',encoding='utf8')  # bytes对象从str使用指定的编码构建
print(cafe)  # b'caf\xc3\xa9'
print(cafe[0])  # 99  # 各个元素是0~255的整数
print(cafe[:1])  # b'c'  # 切片还是bytes对象,即使是只有一个字节的切片cafe_arr = bytearray(cafe)
print(cafe_arr)  # bytearray(b'caf\xc3\xa9')  bytearray没有字面量表示
print(cafe_arr[-1:])  # bytearray(b'\xa9') bytearray切片还是bytearray"""# fromhex:解析十六进制数字对(数字对之间的空格是可选的),构建二进制序列
# print(bytes.fromhex('31 4B CE A9'))"""
构建bytes和bytearray实例海可以调用各自的构造方法,传入以下参数:
1.一个str对象和一个encoding关键紫参数
2.一个可迭代对象,提供0~255之间的整数
3.一个整数,使用空字节创建对应长度的二进制序列
4.一个实现了缓冲协议的对象如: bytes,bytearray,memoryview,array.array
"""
# 例
# 4-3使用数组中的原始数据初始化bytes对象"""import array
numbers = array.array('h',[-2,-1,0,1,2])  # 指定类型代码h,创建一个短整型数组
octets = bytes(numbers)  # 保存组成numbers的字节序列的副本
print(octets)  # b'\xfe\xff\xff\xff\x00\x00\x01\x00\x02\x00'是表示那五个短整数的10个字节"""# 结构题和内存视图
"""struct模块提供了一些函数,把打包的字节序列转换成不同类型字段组成的元组
示例:memoryview和struct处理gif图像.py"""#  4.3 基本的编解码器# 4-5使用3个编解码器编码字符串
# for codec in ['latin_1','utf-8','utf-16']:
#     print(codec,'El Niño'.encode(codec),sep='\t')
# print(b'El Ni\xc3\xb1o'.decode('utf8'))"""
latin1 : 一种重要的编码,是其他编码的基础
cp1252 : Microsoft制定的latin1的超集
cp437 : IBM PC最初的字符集
gb2312 : 编码简体中文的陈旧字符集
utf-8 : 目前web中最常用的编码,与ASCII兼容
utf-16le : 16位编码方案的一种
"""# 4.4了解编解码问题# 4.4.1处理UnicodeEncodeError"""多数非UTF编码只能处理Unicode的一个子集
把文本转换成字节序列时,如果目标编码中没有定义某个字符,那就会抛出UnicodeEncodeError异常
除非把errors参数传给编码方法或者函数,对错误进行特殊处理"""# 4-6 编码成字节序列:成功和错误处理
# city = b'S\xc3\xa3o paulo'.decode(encoding='utf8')
# print(city)"""city = 'São paulo'
print(city.encode('utf8'))
print(city.encode('utf16'))  # b'\xff\xfeS\x00\xe3\x00o\x00 \x00p\x00a\x00u\x00l\x00o\x00'
print(city.encode('iso8859_1'))  # b'S\xe3o paulo'
# print(city.encode('cp437'))  # 报错 UnicodeEncodeError
print(city.encode('cp437',errors='ignore'))
# b'So paulo'  悄无身息地跳过无法处理的字符
print(city.encode('cp437',errors='replace'))
# b'S?o paulo' 把无法编码的字符替换成'?'
print(city.encode('cp437',errors='xmlcharrefreplace'))
# b'São paulo' 把无法编码的字符替换成xmlsh实体"""# 4.4.2 处理UnicodeDecodeError
"""把二进制序列转换成文本时,遇到无法转换的字节序列时抛出UnicodeDecodeError"""# 4-7 解码字节序列:成功和错误处理
"""
octets = b'Montr\xe9al'
print(octets.decode('cp1252'))  # Montréal 正常解码
# iso8859_7用于编码希腊文
print(octets.decode('iso8859_7'))  # Montrιal 没有抛出错误
# koi8_r用于编码俄文
print(octets.decode('koi8_r'))  # MontrИal
# print(octets.decode('utf8'))  # 报错 不是有效的utf8字节序列
print(octets.decode('utf8',errors='replace'))  # Montr�al
"""# 4.4.3使用预期之外的编码加载模块时抛出SyntaxError
"""
python3的源码默认使用utf8编码
python2使用的是ASCII
在文件顶部添加 # coding:cp1252可以指定编码方式
"""# 4.4.4如何找出字节序列的编码
"""Chardet能识别所支持的30种编码"""#4.4.5 BOM:有用的鬼符
"""BOM(byte-order mark)指的是字节序标记
小字节序:各个码位的最低有效字节在前面'E' 的 码位时U+0045(十进制69),在字节偏移的第二位和第三位编码为69和0
大字节序:'E' 的编码为0和69"""# u16 = 'São paulo'
# print(u16.encode('utf16')) # b'\xff\xfeS\x00\xe3\x00o\x00 \x00p\x00a\x00u\x00l\x00o\x00'
# # 即这里的b'\xff\xfe,指明编码时使用intel CPU的小字节序
#
# print(list(u16))# 4.5处理文本文件
"""Unicode三明治1.对于输入来说,尽可能早地把输入的字节序列解码成字符串2.三明治中的肉片时程序的业务逻辑,在这里只能处理字符串对象,在其他处理过程钟一定不能编码或解码3.对于输出来说,要尽可能晚地把字符串编码成字节序列"""# open('cafe.txt','w',encoding='utf8').write('café')
# open('cafe.txt').read()  # 'caf茅'  本机# 4.6 为了正确比较而规范化Unicode字符串# s1 = 'café'
# s2 = 'cafe\u0301'
# print(s1, s2)
# # >>>café café
# print(len(s1), len(s2))
# # >>>4 5
# print(s1 == s2)  # False"""é和e\u0301在Unicode标准中叫做标准等价物但python看到的是不同的码位序列,因此判定不相等这个问题可以使用Unicodedata.normalize()提供的Unicode规范化来解决Unicodedata.normalize()第一个参数:'NFC' 使用最少的码位来构成等价字符串'NFD'  把组合字符分解成基字符和单独的组合字符'NFKC'  K表示兼容性 是较为严格的规范化形式 μ(希腊字母) U+03BC 和 微符号 μ U+00B5'NFKD' 'NFKC''NFKD'可能会在规范化的过程中损失或者曲解意思不能用于持久存贮"""
# normalize函数示例
"""from unicodedata import normalize
s1 = 'café' # 作为组合字符
s2 = 'cafe\u0301' # 分解为基字符和重音符
print(len(s1), len(s2))
# >>>4 5
print(len(normalize('NFC', s1)), len(normalize('NFC', s2)))
# >>> 4 4
print(len(normalize('NFD', s1)), len(normalize('NFD', s2)))
# >>> 5 5
print(normalize('NFC',s1) ==normalize('NFC',s2))  # True
print(normalize('NFD',s1) ==normalize('NFD',s2))  # True"""# NFC的特殊情况
"""from unicodedata import normalize ,name
ohm = '\u2126'
print(ohm)
print(name(ohm))  # OHM SIGN 电阻单位欧姆Ω
ohm_c = normalize('NFC',ohm)
print(name(ohm_c))  # GREEK CAPITAL LETTER OMEGA 希腊小写字母omega
print(ohm == ohm_c) # False
print(normalize('NFC', ohm) == normalize('NFC', ohm_c))# True"""# NFKC示例
"""from unicodedata import normalize ,name
half = '\u00BD'
print(half)
print(normalize('NFKC', half))  # 1⁄2 分解成3个字符
four_squared = '4²'
print(normalize('NFKC', four_squared))  # 42  分解成4 2micro = '\u00B5'
micro_kc = normalize('NFKC',micro)
print(micro,micro_kc)  # μ μprint(ord(micro), ord(micro_kc)) # 181 956
print(name(micro), name(micro_kc))
# >>>MICRO SIGN          GREEK SMALL LETTER MU"""# 4.6.1大小写折叠
# 把所有文本变成小写,再做其他转换  这个功能由str.casefold()支持
# 一般情况下  str.casefold()和lower()结果一样
#     特殊情况:
#         μ变成小写的希腊字母μ,但在大多数字体显示效果一样
#         德语的Eszett会变成ss# 4.6.2规范化文本实用函数
# normeq.py# 4.6.3 极端规划化 去掉变音符号
# sanitize.py# 4.7 Unicode文本排序
# 使用locale.strxfrm函数做排序的键
# import locale
# locale.setlocale(locale.LC_COLLATE,'pt_BR.UTF-8')
# locale.Error: unsupported locale setting 操作系统不支持
# 在sorted中使用 key= locale.strxfrm 就可以使用区域设置中的区域规则来作为排序的依据# 4.8 Unicode数据库
"""Unicode标准提供了一个完整的数据库:包括码位和字符名称之间的映射各个字符的元数据字符之间的关系"""# 元数据示例
"""import unicodedata
import re
re_digit = re.compile(r'\d')
sample = '1\xbc\xb2\u0969\u136b\u216b\u2466\u2480\u3285'for char in sample:print('U+%04x'%ord(char),char.center(6),'re_dig' if re_digit.match(char) else '-','isdig' if char.isdigit() else '-','isnum' if char.isnumeric() else '-',format(unicodedata.numeric(char),'5.2f'),unicodedata.name(char),sep = '\t')"""# 4.9 支持字符串和字节序列的双模式API
# 提供的函数能接受字符串或者字节序列为参数,然后根据类型进行特殊处理
# re和os模块有这样的函数# 4.9.1正则表达式中的字符串和字节序列
# ramanujan.py# 4.9.2 os函数中的字符串和字节序列

探索编码默认值 default_encoding.py

# 探索编码默认值
import sys,locale
expressions = """locale.getpreferredencoding()type(my_file)my_file.encodingsys.stdout.isatty()sys.stdout.encodingsys.stdin.isatty()sys.stdin.encodingsys.stderr.isatty()sys.stderr.encodingsys.getdefaultencoding()sys.getfilesystemencoding()"""my_file = open('dummy','w')
for expression in expressions.split():value = eval(expression)print(expression.rjust(30),'->',repr(value))"""结果:locale.getpreferredencoding() -> 'cp936'  # 打开文件的默认编码type(my_file) -> <class '_io.TextIOWrapper'>my_file.encoding -> 'cp936'sys.stdout.isatty() -> Falsesys.stdout.encoding -> 'utf-8'sys.stdin.isatty() -> Falsesys.stdin.encoding -> 'utf-8'sys.stderr.isatty() -> Falsesys.stderr.encoding -> 'utf-8'sys.getdefaultencoding() -> 'utf-8'sys.getfilesystemencoding() -> 'utf-8'"""# 结论:不要依赖默认值
4-4使用memoryview和struct查看gif图像的首部
# 4-4使用memoryview和struct查看gif图像的首部import struct
fmt = '<3s3sHH' # '<' 小字节序,'3s3s'两个3字节序列,'HH'两个16位二进制整数
with open('sda.gif','rb') as fp:img = memoryview(fp.read())  # 使用内存中的文件创建了一个memoryview对象header = img[:10]  # memoryview对象的一个切片
tmp = bytes(header)  # 转换成字节序列以显示
print(header)
print(tmp)print(struct.unpack(fmt,header))  # 拆包memoryview对象,得到一个元组,包含类型,版本,宽度和高度del header
del img  # 删除引用释放memoryview实例所占用的内存
# 4.6.2规范化文本实用函数
# normeq.py
# Utility Function for normalized Unicode string C oparosonfrom unicodedata import normalize
def nfc_equal(str1,str2):return normalize('NFC',str1) == normalize('NFC',str2)def fold_equal(str1,str2):return (normalize('NFC',str1).casefold() ==normalize('NFC',str2).casefold())if __name__ == '__main__':s1 = 'café'  # 作为组合字符s2 = 'cafe\u0301'  # 分解为基字符和重音符print(s1 == s2)print(nfc_equal(s1, s2))fold_equal('A','a')
# 4.6.3 极端规划化 去掉变音符号
# sanitize.py
import unicodedata
import stringdef shave_marks(txt):'''去掉全部变音符号'''norm_txt = unicodedata.normalize('NFD',txt)shaved = ''.join(c for c in norm_txtif not unicodedata.combining(c))return unicodedata.normalize('NFC',shaved)if __name__ == '__main__':t = '4² \u00BD café'print(shave_marks(t))
# 4.9.1正则表达式中的字符串和字节序列
# ramanujan.py
import re
re_numbers_str = re.compile(r'\d+')
re_words_str = re.compile(r'\w+')
re_numbers_bytes = re.compile(rb'\d+')
re_words_bytes = re.compile(rb'\w+')text_str = ("Ramanujan saw \u0be7\u0bed\u0be8\u0bef""as 1729 = 1³+12³ = 9³ + 10³.") # 在字符串编译时与前一个拼接起来
text_bytes = text_str.encode('utf8') # 字节序列只能用于字节序列的正则表达式搜索
print('Text',repr(text_str),sep='\n')
print('Numbers')
print(' str :',re_numbers_str.findall(text_str)) # 能匹配泰米尔数字和ASCII数字
print(' bytes :',re_numbers_bytes.findall(text_bytes)) # 只能匹配ASCii数字
print('words')
print(' str :',re_words_str.findall(text_str))  # 能匹配字母\上标\泰米尔数字\和sacii数字
print(' Bytes :',re_words_bytes.findall(text_bytes)) # 只能匹配ascii的字母和数字"""
Text
'Ramanujan saw ௧௭௨௯as 1729 = 1³+12³ = 9³ + 10³.'
Numbersstr : ['௧௭௨௯', '1729', '1', '12', '9', '10']bytes : [b'1729', b'1', b'12', b'9', b'10']
wordsstr : ['Ramanujan', 'saw', '௧௭௨௯as', '1729', '1³', '12³', '9³', '10³']Bytes : [b'Ramanujan', b'saw', b'as', b'1729', b'1', b'12', b'9', b'10']"""

35岁学Python,也不知道为了啥?

读书笔记:《流畅的Python》第4章 文本和字节序列相关推荐

  1. 读书笔记-流畅的python(1-6章)

    前言:这正是本书的主要目的:着重讲解这门语言的基本惯用法,让你的代码简洁.高效且可读,把你打造成熟练的 Python 程序员. 自己总结学习作为输出,很多为了节省时间只是复制粘贴,不具有广泛意义 第一 ...

  2. 《流畅的python》第四章 文本和字节序列

    U1. 把码位转换成字节序列的过程是编码(encode),把字节序列转换成码位的过程是解码(decode). 2. bytes和bytearray对象的各个元素是介于0--255之间的整数. 3. 结 ...

  3. [流畅的Python][4][文本和字节序列]

    第4章 文本和字节序列 人类使用文本,计算机使用字节序列.--------Esther Nam和Travis Fischer Python3明确地区分了人类可读的文本字符串和原始的字节序列 4.1 字 ...

  4. 【读书笔记】.NET本质论第四章-Programming with Type(Part Two)

    欢迎阅读本系列其他文章: [读书笔记].NET本质论第一章 The CLR as a Better COM [读书笔记].NET本质论第二章-Components(Part One) [读书笔记].N ...

  5. 流畅的python学习笔记(三):数据结构(3:文本和字节序列)

    文本和字节序列 大纲 1. 字符问题 2. 字节概要 2.1 结构体和内存视图 3. 基本的编解码器 4. 了解编解码问题 4.1 处理UnicodeEncodeError 4.2 处理Unicode ...

  6. 流畅的python读书笔记④:文本和字节序列

    人类使用文本,计算机使用字节序列. --Esther Nam 和 Travis Fischer "Character Encoding and Unicode in Python" ...

  7. 【读书笔记】用Python获取A股行情数据的4种方法

    本人大三在校小学渣一枚,非金融专业,也从来没有过股票期货等金融产品的投资经验,但最近收到了清华出版社赠送的<深入浅出Python量化交易实战>一书,因为平时对数据科学和机器学习都比较感兴趣 ...

  8. 《Real-Time Rendering 4th Edition》读书笔记--简单粗糙翻译 第七章 阴影 Shadows

    写在前面的话:因为英语不好,所以看得慢,所以还不如索性按自己的理解简单粗糙翻译一遍,就当是自己的读书笔记了.不对之处甚多,以后理解深刻了,英语好了再回来修改.相信花在本书上的时间和精力是值得的. -- ...

  9. 《Real-Time Rendering 4th Edition》读书笔记--简单粗糙翻译 第五章 着色基础 Shading Basics

    写在前面的话:因为英语不好,所以看得慢,所以还不如索性按自己的理解简单粗糙翻译一遍,就当是自己的读书笔记了.不对之处甚多,以后理解深刻了,英语好了再回来修改.相信花在本书上的时间和精力是值得的. -- ...

最新文章

  1. UserWarning: Label not :NUMBER: is present in all training examples
  2. 企业部署Linux应用将拥有更低的整体拥有成本
  3. Expression Blend实例中文教程(9) - 行为快速入门Behaviors
  4. 关联tomcat源代码
  5. visual studio C语言指针提示:使用未初始化的内存xx
  6. DSP F28335的SCI模块
  7. 匈牙利命名法的优缺点
  8. 计算机一级excel如何选择2个,2017年计算机一级excel操作题(2)
  9. Windows平台下搭建自己的Git服务器
  10. TensorFlow笔记(11) GoolgeNet
  11. What is WCF
  12. vue 实现压缩图片上传到oss
  13. 查看指定进程io状态的iotop命令
  14. 注释 向 Java 代码中添加元数据
  15. 互联网浏览本地html,如何加载本地HTML文件,如果没有互联网连接
  16. 解决方案大全ImportError: libta_lib.so.0: cannot open shared object file: No such file or directory
  17. 解决Ubuntu系统找不到进程,但是GPU显存占满问题
  18. POJ 1002 UVA 755 487--3279 电话排序 简单但不容易的水题
  19. 标准ACL(Standard ACL)
  20. 2022-2028年中国产学研合作行业深度调查与战略咨询报告

热门文章

  1. 南京理工大学紫金学院 Javaweb跨平台开发实践
  2. 2021年,入局直播电商是最好的时机吗?
  3. 如何设计成功的游戏关卡
  4. 个人申办在职人才引进
  5. 我的世界服务器邮件指令是什么,我的世界OP指令是什么 我的世界OP指令大全
  6. 高位在前低位在后是啥意思_主力究竟在洗盘还是出货?其实这10张“分时图”已经告诉你一切了,再忙选股前也要花10分钟看看...
  7. mysql索引创建规则、联合与一般索引、执行计划、索引选择,索引重建与下推
  8. 服务器响应显示您没有权限下载此文件如何解决
  9. IDEA自定义上下左右快捷键
  10. 安装IIS时,出现‘请将windows XP Professional Service Pack 3 CD 光盘插入’及类似问题解决方法