导语:本文章记录了本人在学习Python基础之数据结构篇的重点知识及个人心得,打算入门Python的朋友们可以来一起学习并交流。
本章重点:
1、了解字符字节等概念,编解码问题; 2、熟悉字符的规范化处理和双模式API。
编解码例子:
s="São Paulo"
a=s.encode('utf8')
print(a)#b'S\xc3\xa3o Paulo'
b=a.decode("utf8")
print(b)
output:São Paulo
一种重要的编码, 是其他编码的基础。
例如 cp1252 和Unicode( 注意, latin1 与 cp1252 的字节值是一样的, 甚至连码位也相同) 。Microsoft 制定的 latin1 超集
, 添加了有用的符号, 例如弯引号和€( 欧元) ; 有些 Windows 应用把它称为“ANSI”, 但它并不是 ANSI 标准。目前 Web 中最常见的 8 位编码; 与 ASCII 兼容
( 纯 ASCII 文本是有效的 UTF-8 文本) 。了解有关Unicode错误的处理方法。
编码出现的错误在于编码器可能无法对字符串编码,以中英文字符串为例:
city="DaLian大连"
print(city.encode("utf8"))#b'DaLian\xe5\xa4\xa7\xe8\xbf\x9e'
print(city.encode("iso8859_1"))
输出报错:
Traceback (most recent call last):
File "D:\韩文承\编程工作空间\Fluent Python\section4-1.py", line 10, in <module>
print(city.encode("iso8859_1"))
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 6-7: ordinal not in range(256)
原因在于这个latin1不会对中午编码,所以我们需要处理这个EncodeError,处理如下:
print(city.encode("iso8859_1",errors="ignore"))#b'DaLian'
print(city.encode("iso8859_1",errors="replace"))#b'DaLian??'
print(city.encode("iso8859_1",errors="xmlcharrefreplace"))#b'DaLian大连'
想了解更多错误处理方式可查阅Python官方Library: https://docs.python.org/3/lib...
解码出现的错误在于陈旧的解码器能解码任何字节序列而不抛出错误,有时会解码出无用的、乱码的字符。以包含变音符号的字节序列为例:
c=b"Montr\xe9al"
print(c.decode("iso8859_1"))#Montréal
print(c.decode("cp1252"))#Montréal
print(c.decode("cp437"))#MontrΘal 输出已经有问题了
print(c.decode("koi8_r"))#MontrИal KOI8_R是编码俄文的,此处输出了俄文字母
print(c.decode("utf8"))
报错:
Traceback (most recent call last):
File "D:\韩文承\编程工作空间\Fluent Python\section4-1.py", line 19, in <module>
print(c.decode("utf8"))
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 5: invalid continuation byte
原因在于utf_8检测到c不是有效utf_8字符串,抛出UnicodeDecodeError。处理如下:
print(c.decode("utf8",errors="replace"))#Montr�al。用�替代无法解码的字节
如果加载的模块中包含utf_8之外的数据,那么解释器会报错SyntaxError。
Chardet是Python的一个库,可以检测出未知字节序列的编码方式。 不要在二进制模式中打开文本文件。即使想判断编码,也该用Chardet!
字节序标记,这个标记针对非单字节非字符串外的其余数据(如short,int)指明字节存储的方式,具体分为大端存储和小端存储。
大端存储第一个字节是高位,容易判断数值的正负;
小端存储第一个字节是地位,容易进行数值的运算。
需要注意:TCP/IP协议规定网络字节序为大端字节序。这意味着主机字节序如果是小端存储必须转化为大端字节序才能通过网络发送数据。
To Learn More:https://zhuanlan.zhihu.com/p/...
编码默认值 在多系统处理文件时应显式制定编码,否则容易出现默认编码器无法解码字节序列的情况。 编辑器默认编码查询:locale.getpreferredencoding()#cp936
Unicode三明治原则
我们可以用一个简单的原则处理编码问题: 字节序列->字符串->字节序列
。就是说程序中应当仅处理字符串,当需要保存到文件系统或者传输的时候,编码为字节序列。
Unicode字符串规范化 码位规范化函数:unicodedata.normalize(格式,字符串) 格式参数:
对大多数应用来说NFC是最好的规范化形式。
from unicodedata import normalize
d="café"
e="cafe\u0301"
print(normalize("NFC",d)==normalize("NFC",e))#True
print(normalize("NFD",d)==normalize("NFD",e))#True
规范化之后两个不同的码位相等的。
保存文件之前最好用规范化函数unicodedata.normalize(“NFC”,字符串)清洗字符串
大小写折叠函数:str.casefold() 自Python3.4起,str.lower()和str.casefold()不同的结果有116个码位,占Unicode命名的总字符的0.11%
Unicode 排序:unicode collation algorithm, UCA 使用 PyUCA 库。 下载地址:https://pypi.python.org/pypi/...
双模式是指标准库中一些函数能够接受字符串或字节序列为参数,并根据类型进行处理。 API(Application Programming Interface)即应用程序接口。可以把 API 理解为一个软件组件或是一个 Web 服务与外界进行的交互的接口。通俗的理解是程序和程序之间的交互,交互就是传递数据,触发功能。
正则表达式:可以匹配文本片段的模式。
通配符:
用反斜线对特殊符号进行转义:
有时我们只想用特殊符号如dot“."的字面意思,而非作为通配符使用。例如匹配网站”baidu.com“中的点就需要转义,变成"baidu\.com",即只匹配”baidu.com“
字符集:
表示欲匹配字符的集合,相比较通配符中的点号而言范围更小一些。例如[0-9A-F]可以匹配一个十六进制的字符。
注意:一个字符集只能匹配一个字符,除非配合数量限定符使用!
预定义字符集
选择符和子模式:
此项欲匹配的范围比字符集还要小。比如你只想匹配python和people这两个单词,就可以用管道符号(|),即“python|people"。
如果操作的不是整个模式partern而是模式的一部分,圆括号括起来的部分称作子模式,即“p(ython|eople)”
函数 | 描述 |
---|---|
re.compile(pattern, flags=0) | 根据正则表达式的字符串创建模式对象 |
re.search(pattern, string, flags=0) | 在字符串中寻找模式 |
re.match(pattern, string, flags=0) | 在字符串的开始处匹配模式 |
re.split(pattern, string, maxsplit=0, flags=0) | 根据模式的匹配项来分割字符串 |
re.findall(pattern, string, flags=0) | 列出字符串中模式的所有匹配项 |
re.finditer(pattern, string, flags=0) | 返回一个迭代器,其中包含满足正则表达式要求的match objects |
re.sub(pattern, repl, string, count=0, flags=0) | 将字符串中所有pat的匹配项用repl替换 |
re.escape(pattern) 将字符串中所有特殊正则表达式字符转义
Tips:re.compile构建模式,对于重复式的匹配效率更高。
flags参数介绍:
MatchObject是一次成功匹配后返回的对象类型,它支持如下的重要方法:
*和+这类数量限定符默认是贪婪的,即尽可能多的匹配满足要求的字符串。只有在其后加上问号?方可变成非贪婪的。 贪婪与非贪婪eg:
import re
greedy=re.compile(r"<.*>")#贪婪
non_greedy=re.compile(r"<.*?>")#非贪婪,利用问号限制
print(greedy.search("<H1>Chapter 1 - 介绍正则表达式</H1>"))
print(non_greedy.search("<H1>Chapter 1 - 介绍正则表达式</H1>"))
输出:
<_sre.SRE_Match object; span=(0, 28), match='<H1>Chapter 1 - 介绍正则表达式</H1>'>
<_sre.SRE_Match object; span=(0, 4), match='<H1>'>
对字符串和字节序列进行re匹配:
import re
text_str = "Ramanujan saw \u0be7\u0bed\u0be8\u0bef as 1729 = 1³ + 12³ = 9³ + 10³."
text_byte=text_str.encode('utf_8')
str_number=re.compile(r"\d+")
str_word=re.compile(r"\w+")
byte_number=re.compile(rb"\d+")
byte_word=re.compile(rb"\w+")
print("str_number",str_number.findall(text_str))
print("str_word",str_word.findall(text_str))
print("byte_number",byte_number.findall(text_byte))
print("byte_word",byte_word.findall(text_byte))
输出:
str_number ['௧௭௨௯', '1729', '1', '12', '9', '10']
byte_number [b'1729', b'1', b'12', b'9', b'10']
str_word ['Ramanujan', 'saw', '௧௭௨௯', 'as', '1729', '1³', '12³', '9³', '10³']
byte_word [b'Ramanujan', b'saw', b'as', b'1729', b'1', b'12', b'9', b'10']
分析:通过分别对字符串和字节序列进行数字、单词字符的匹配操作,容易发现对字节序列的匹配仅限于ASCII中的数字和单词字符,而对字符串的匹配会包含更多的泰米尔数字和上标等其他字符。
To Learn More: https://docs.python.org/3/lib...
用于返回指定的文件夹包含的文件或文件夹的名字的列表。这个列表以字母顺序。
如果 filename 是 str 类型或bytes 类型,使用sys.getfilesystemencoding() 返回的编解码器把 filename 编码成字节序列; 否则, 返回未经修改的 filename 字节序列。
如果 filename 是 bytes 类型或 str 类型, 使用sys.getfilesystemencoding() 返回的编解码器把 filename 解码成字符串; 否则, 返回未经修改的 filename 字符串。