第二章:字符串和文本
2.1 使用多个界定符分割字符串
将一个字符串分割为多个字段,但是分隔符 (还有周围的空格) 并不是固定的。
使用 re.split() 方法 :允许你为指定多个分隔符
1 | import re |
注意:
如果加了分组,那么就会连分组一起保留:
1
2
3
4
5
6
7 import re
line = 'asdf fjdk; afed, fjek,asdf, foo'
x = re.split(r'([\s;,]\s*)',line)
print(x)
# ['asdf', ' ', 'fjdk', '; ', 'afed', ', ', 'fjek', ',', 'asdf', ', ', 'foo']如果你不想保留分割字符串,但仍然需要使用到括号来分组正则表达式的话,确保你的分组是非捕获分组,形如 (?:…) 。
1 re.split(r'(?:,|;|\s)\s*', line)
2.2 字符串开头或结尾匹配
str.startswith() 或者是 str.endswith() 方法。
注意 : 参数可以是一个元组,表示
或
的关系
1 | string = 'trainingfile/training1.py' |
2.3 用 Shell 通配符匹配字符串
fnmatch 模块提供了两个函数——fnmatch() 和 fnmatchcase()
fnmatch() 函数匹配能力介于简单的字符串方法和强大的正则表达式之间。
1 | from fnmatch import fnmatch, fnmatchcase |
2.4 字符串匹配和搜索
str.find()
re.match()
re.search()
re.findall()
re.finditer()
2.5 字符串搜索和替换
str.replace()
1 | text = 'yeah, but no, but yeah, but no, but yeah' |
re.sub()
1 | import re |
re.sub甚至可以传入回调函数:
1
2
3
4
5
6
7
8
9
10
11
12
13 import re
from calendar import month_abbr
datepat = re.compile(r'(\d+)/(\d+)/(\d+)')
text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
def change_date(m):
mon_name = month_abbr[int(m.group(1))]
return '{} {} {}'.format(m.group(2), mon_name, m.group(3))
print(datepat.sub(change_date, text))
# Today is 27 Nov 2012. PyCon starts 13 Mar 2013.
re.subn()知道有发生了多少次替换
2.6 字符串忽略大小写的搜索替换
re.IGNORECASE 标志参数
1 | import re |
2.7 最短匹配模式(非贪婪模式)
模式中的 * 操作符后面加上? 修饰符
1 | str_pat = re.compile(r'\"(.*)\"') |
2.8 多行匹配模式
标志参数 re.DOTALL
1 | import re |
2.9 将 Unicode 文本标准化
在 Unicode 中,某些字符能够用多个合法的编码表示,需要确保所有字符串在底层有相同的表示。
1 | s1 = 'Spicy Jalape\u00f1o' |
使用 unicodedata 模块先将文本标准化
1 | import unicodedata |
2.10 在正则式中使用 Unico
默认情况下 re 模块已经对一些 Unicode 字符类有了基本的支持。比如,\d 已经匹配任意的 unicode 数字字符
1 | import re |
2.11 删除字符串中不需要的字符
strip()
lstrip()
rstrip()
注意 : strip()删除的是开始或结尾指定字符,不单单是空白
1
2
3
4 text = '12345678589'
print(text.strip('19')) # 234567858
print(text.lstrip('19')) # 2345678589
print(text.rstrip('19')) # 1234567858
2.12 审查清理文本字符串
你可能想消除整个区间上的字符或者去除变音符。使用str.translate()
str.translate():
构建一个映射表,让对应的字符串映射成另一个字符串
1 | s = 'pýtĥöñ\fis\tawesome\r\n' |
2.13 字符串对齐
ljust()
rjust()
center()
1 | text = 'hyl' |
format()
1 | text = 'hyl' |
2.14 合并拼接字符串
join()
python的接口是鸭子类型,所以join不仅支持可迭代对象,还支持生成器
1
2
3
4
5
6
7
8
9 def gen():
for num in range(9):
yield str(num)
g = gen()
x = ''.join(g)
print(x)
# 012345678
当我们使用加号 (+) 操作符去连接大量的字符串的时候是非常低效率的,因为加号连接
- 引起内存复制
- 引起垃圾回收操作
下面的代码建议不能写:
1
2
3
4 s = ''
for p in parts:
s += p而是应该先收集所有的字符串片段然后再将它们连接起来 :
1 s = ''.join(parts)还可以使用生成器:
1
2 data = ['ACME', 50, 91.1]
','.join(str(d) for d in data)
2.15 字符串中插入变量
format()
format_map() : 待被替换的变量在变量域中找
1 | name = 'hyl' |
format 和 format_map() 的一个缺陷就是它们并不能处理变量缺失的情况
1 | name = 'hyl' |
为此,我们可以定义一个继承dict,实现__messing__
的类:
__messing__
方法可以让你定义如何处理缺失的值。
1 | class safesub(dict): |
我们甚至可以将其封装起来:
1 | import sys |
这其实就是f-string
2.16 以指定列宽格式化字符串
有一些长字符串,想以指定的列宽将它们重新格式化。
使用 textwrap 模块
1 | import textwrap |
2.17 在字符串中处理 html 和 xml
- 将 HTML 或者 XML 实体如 &entity; 或 code; 替换为对应的文本。
- 转换文本中特定的字符 (比如 <, >, 或 &)。
html.escape()
1 | import html |
2.18 字符串令牌解析
你有一个字符串,想从左至右将其解析为一个令牌流。
- 令牌化是指在分隔符的基础上将一个字符串分割为若干个子字符串。
- 例如,分隔符;分割字符串
ac;bd;def;e
为四个子字符串ac,bd,def和e。
- 模式对象有一个 scanner() 方法
- 这个方法会创建一个 scanner 对象,在这个对象上不断的调用 match() 方法会一步步的扫描目标文本,每步一个匹配。
1 | import re |
所以我们可以将其转为生成器:
1 | def generate_tokens(pat, text): |
2.19 实现一个简单的递归下降分析器
你想根据一组语法规则解析文本并执行命令,或者构造一个代表输入的抽象语法树。
(看不懂,略)
2.20 字节字符串上的字符串操作
在字节字符串上执行普通的文本操作 (比如移除,搜索和替换)。
字节字符串同样也支持大部分和文本字符串一样的内置操作
字节字符串的索引操作返回整数而不是单独字符。
1
2
3
4
5a = 'Hello World'
a[0] # H
b = b'Hello World'
b[0] # 72字节字符串不会提供一个美观的字符串表示,也不能很好的打印出来,除
非它们先被解码为一个文本字符串。1
2
3s = b'Hello World'
print(s) # b'Hello World'
print(s.decode('ascii')) # Hello World不存在任何适用于字节字符串的格式化操作