字符串
常用基本操作
- 反转字符串
- 字符串切片操作
- join串联字符串
- 分割字符串
- 替换
- 子串判断
- 去空格
- 字符串的字节长度
反转字符串
1 | s = 'python' |
字符串切片操作
生成 1 到 15 的序列,并在满足条件的索引处,替换为 java 或 python。
1 | java, python = 'java', 'python' |
输出结果,如下图:

join 串联字符串
用下划线 _ 连接字符串 mystr:
1 | mystr = ['I', 'love', 'Python'] |

分割字符串
根据指定字符或字符串,分割一个字符串时,使用方法 split。
join 和 split 可看做一对互逆操作:
1 | 'I_love_Python'.split('_') |
替换
字符串替换,使用 replace 方法。
如下字符串,小写的 o 全部替换为大写的 O:
1 | s = 'i love python'.replace('o', 'O') |
子串判断
判断 a 串是否为 b 串的子串。
方法一,使用in:
1
2
3
4
5a = 'our'
b = 'flourish'
r = True if a in b else False
r
True
方法二,使用方法find,返回字符串b中匹配子串a的最小索引
1
2
3
4a = 'our'
b = 'flourish'
b.find(a)
2
去空格
清洗字符串时,位于字符串开始和结尾的空格,有时需要去掉,strip 方法能实现。
如下字符串,使用 strip,清理字符串开头和结尾的空格和制表符。
1 | a = ' \tI love python \b\n' |
字符串的字节长度
encode 方法对字符串编码后:
1 | def str_byte_len(mystr): |

正则表达式
字符串封装的方法,处理一般的字符串操作,还能应付。但是,稍微复杂点的字符串处理任务,需要靠正则表达式,简洁且强大。
首先,导入所需要的模块 re:
1 | import re |
首先,认识常用的元字符:
| 符号 | 说明 |
| ———- | ——————————————————— |
|.| 匹配除 “\n” 和 “\r” 之外的任何单个字符 |
|^| 匹配字符串开始位置 |
|$| 匹配字符串中结束的位置 |
|*| 前面的原子重复 0 次、1 次、多次 |
|?| 前面的原子重复 0 次或者 1 次 |
|+| 前面的原子重复 1 次或多次 |
|{n}| 前面的原子出现了 n 次 |
|{n,}| 前面的原子至少出现 n 次 |
|{n,m}| 前面的原子出现次数介于 n-m 之间 |
|()| 分组,输出需要的部分 |
再认识常用的通用字符:
| 符号 | 说明 |
| ———- | ————————————————————————- |
|\s| 匹配空白字符 |
|\w| 匹配任意字母/数字/下划线 |
|\W| 和小写 w 相反,匹配任意字母/数字/下划线以外的字符 |
|\d| 匹配十进制数字 |
|\D| 匹配除了十进制数以外的值 |
|[0-9]| 匹配一个 0~9 之间的数字 |
|[a-z]| 匹配小写英文字母 |
|[A-Z]| 匹配大写英文字母 |
正则表达式,常会涉及到以上这些元字符或通用字符,下面通过 14 个细分的与正则相关的小功能,讨论正则表达式。
search 第一个匹配串
使用正则模块,search 方法,找出子串第一个匹配位置。
1 | import re |
match 与 search 不同
正则模块中,match、search 方法匹配字符串不同
具体不同:
- match 在原字符串的开始位置匹配
- search 在字符串的任意位置匹配
原字符串:
1 | s = 'flourish' |
寻找模式串 our,使用 match 方法:
1 | recom = re.compile('our') |
使用 search 方法:
1 | s = 'flourish' |
那么,什么字符串才能使用 match 方法匹配到 our?比如,字符串 ourselves,ours 才能 match 到 our。
1 | s = 'ourselves' |
finditer 匹配迭代器
使用正则模块,finditer 方法,返回所有子串匹配位置的迭代器。
通过返回的对象 re.Match,使用它的方法 span 找出匹配位置。
1 | import re |
findall 所有匹配
正则模块,findall 方法能查找出子串的所有匹配。
原字符串 s:
1 | s = '一共20行代码运行时间13.59s' |
目标查找出所有所有数字:通用字符 \d 匹配一位数字 [0-9],+ 表示匹配数字前面的一个字符 1 次或多次。
1 | pat = r'\d+' |
返回一个列表,找到三个数字 20、13、59,没有达到预期,期望找到 20、13.59。
因此,需要修改正则表达式。接下来看如下的案例:
案例
匹配浮点数和整数
?表示前一个字符匹配 0 或 1 次.?表示匹配小数点(.)0 次或 1 次。
匹配浮点数和整数,第一版正则表达式:r'\d+\.?\d+',图形化演示,此正则表达式的分解演示:

1 | s = '一共20行代码运行时间13.59s' |
上面的正则表达式 r'\d+\.?\d+',能适配所有情况吗?
1 | s = '一共2行代码运行时间1.66s' |
观察结果,没有匹配到数字 2。
正则难点之一,需要考虑全面、足够细心,才可能写出准确无误的正则表达式。
出现问题原因:r'\d+\.?\d+',后面的 \d+ 表示至少有一位数字,因此,整个表达式至少会匹配两位数。
修复问题,重新优化正则表达式,将最后的 + 后修改为 *,表示匹配前面字符 0 次、1 次或多次。
最终正则表达式为:r'\d+\.?\d*',正则分解图:

1 | s = '一共2行代码运行时间1.66s' |
匹配正整数
案例:写出匹配所有正整数的正则表达式。
如果这样写:^\d*$,会匹配到 0,所以不准确。
如果这样写:^[1-9]*,会匹配 1. 串中 1,不是完全匹配,体会 $ 的作用。
正确写法:^[1-9]\d*$,正则分解图:

1 | s = [-16, 1.5, 11.43, 10, 5] |
re.l忽略大小写
re.l是方法的可选参数,表示忽略大小写。
如下,找出字符串中所有字符 t 或 T 的位置,不区分大小写。
1 | import re |
split 分割单词
正则模块中 split 函数强大,能够处理复杂的字符串分割任务。
如果一个规则简单的字符串,直接使用字符串,split 函数。
如下字符串,根据分割符 \t 分割:
1 | s = 'id\tname\taddress' |
但是,对于分隔符复杂的字符串,split 函数就无能为力。
如下字符串,可能的分隔符有 ,、;、\t、|。
1 | s = 'This,,, module ; \t provides|| regular ; ' |
正则字符串为:[,\s;|]+,\s 匹配空白字符,正则分解图,如下:

1 | s = 'This,,, module ; \t provides|| regular ; ' |
sub 替换匹配串
正则模块,sub 方法,替换匹配到的子串:
1 | content = 'hello 12345, hello 456321' |
compile 预编译
如果要用同一匹配模式,做很多次匹配,可以使用 compile 预先编译串。
案例:从一系列字符串中,挑选出所有正浮点数。
正则表达式为:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$,字符 a|b 表示 a 串匹配失败后,才执行 b 串,正则分解图见下:

首先,生成预编译对象 rec:
1 | s = [-16, 'good', 1.5, 0.2, -0.1, '11.43', 10, '5e10'] |
下面直接使用 rec,匹配列表中的每个元素,不用每次都预编译正则表达式,效率更高。
1 | [ i for i in s if rec.match(str(i))] |
贪心捕获
正则模块中,根据某个模式串,匹配到结果。
待爬取网页的部分内容如下所示,现在想要提取 <div> 标签中的内容。
1 | content = '<h>ddedadsad</h><div>graph</div>aa<div>math</div>' |
如果正则匹配串写做 <div>.*</div>:
1 | result = re.findall(r'<div>.*</div>', content) |
看到返回结果后,如果我们不想保留字符串的<div>和结尾的</div>,那么,就需要使用一对()去捕获。
正则匹配串修改为:<div>(.*)</div>,只添加一对括号。
1 | result = re.findall(r'<div>(.*)</div>', content) |
- 看到结果中已经没有了
<div>和</div>仅使用一对括号,便成功捕获到我们想要的部分 (.*)表示捕获任意多个字符,尽可能多地匹配字符,也被称为贪心捕获(.*)的正则分解图如下所示,.表示匹配除换行符外的任意字符

非贪心捕获
观察上面返回的结果 ['graph</div>aa<div>math'],如果只想要得到两个 <div></div> 间的内容,该怎么写正则表达式?
相比 (.*),仅多添加一个 ?,匹配串为 (.*?)。
1 | content = '<h>ddedadsad</h><div>graph</div>aa<div>math</div>' |
终于得到 2 个 <div> 对间的内容。
这种匹配模式串 (.*?),被称为非贪心捕获。正则图中,红色虚线表示非贪心匹配。
