Python spider入门_2 Python 正则表达式 re 模块

0 前言

python 自1.5 版本起增加了 re 模块,re 模块使 python 拥有全部的正则表达式功能。

python 是自带 re 库的。

compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。(现在你可能看不懂,但后面就懂了)

接下来我会介绍一些 python 中常用的正则表达式处理函数。

参考网站:Python 正则表达式 | 菜鸟教程 (runoob.com)

1 re.match函数

他尝试从字符串起始位置进行匹配,如果不是起始位置匹配成功的话,match() 就返回 none 。

函数语法:

​ re.match(pattern, string, flags=0)

函数参数说明:

参数 描述
pattern 匹配的正则表达式
string 要匹配的字符串
flags 标志位(但愿你没有忘记)

匹配成功 re.match 方法返回一个匹配的对象,否则返回 None 。

我们可以使用 group(num) 或group() 匹配对象函数来获取正则表达式。组的存在与顺序是按照你正则表达式的括号 () 存在与顺序决定的

匹配对象方法 描述
group(num=0) 匹配整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应的元组
groups() 返回一个包含所有小组字符串的的元组,从 1 到所含的小组号

还可以给group添加名字,此时,名字等同于小组号,在正则表达式的对应 () 中最开始添加 ?P 就可以了,把“value”改成你想要的。

例子 1 :

1
2
3
4
5
6
7
import re

pattern1 = 'cat'
pattern2 = 'the'
str1 = 'The cat sit on the mat.'

print(re.match(pattern1, str1)) print(re.match(pattern2, str1)) print(re.match(pattern2, str1, flags=re.I)) print(re.match(pattern2, str1, flags=re.I).span())

运行结果:

1
2
3
4
None
None
<re.Match object; span=(0, 3), match='The'>
(0, 3)

例子 2 :

1
2
3
4
5
6
7
8
9
10
11
12
13
import re

line = "Cats are smarter than dogs"

matchObj = re.match(r'(.*) are (.*?) .*', line, re.M | re.I)

if matchObj:
print("matchObj.group() : ", matchObj.group())
print("matchObj.group(1) : ", matchObj.group(1))
print("matchObj.group(2) : ", matchObj.group(2))
print("matchObj.groups() : ", matchObj.groups())
else:
print("No match!!")

运行结果:

1
2
3
4
matchObj.group() :  Cats are smarter than dogs
matchObj.group(1) : Cats
matchObj.group(2) : smarter
matchObj.groups() : ('Cats', 'smarter')

例子3:

1
2
3
4
5
6
7
8
9
10
11
12
13
import re

line = "Cats are smarter than dogs"

matchObj = re.match(r'(?P<v1>.*) are (?P<v2>.*?) .*', line, re.M | re.I)

if matchObj:
print("matchObj.group() : ", matchObj.group())
print("matchObj.group(1) : ", matchObj.group('v1'))
print("matchObj.group(2) : ", matchObj.group(2))
print("matchObj.groups() : ", matchObj.groups())
else:
print("No match!!")

运行结果:

1
2
3
4
matchObj.group() :  Cats are smarter than dogs
matchObj.group(1) : Cats
matchObj.group(2) : smarter
matchObj.groups() : ('Cats', 'smarter')

2 re.search方法

扫描整个字符串并返回第一个成功的匹配

函数语法:

​ re.serach(pattern, string, flag=0)

例子 1 :

1
2
3
4
5
6
7
8
9
10
import re

pattern1 = 'cat'
pattern2 = 'the'
str1 = 'The cat sit on the mat.'

print(re.search(pattern1, str1))
print(re.search(pattern2, str1))
print(re.search(pattern2, str1, flags=re.I))
print(re.search(pattern2, str1, flags=re.I).span())

运行结果:

1
2
3
4
<re.Match object; span=(4, 7), match='cat'>
<re.Match object; span=(15, 18), match='the'>
<re.Match object; span=(0, 3), match='The'>
(0, 3)

例子 2 :

1
2
3
4
5
6
7
8
9
10
11
12
13
import re

line = "Cats are smarter than dogs"

searchObj = re.search(r'(.*) are (.*?) .*', line, re.M | re.I)

if searchObj:
print("searchObj.group() : ", searchObj.group())
print("searchObj.group(1) : ", searchObj.group(1))
print("searchObj.group(2) : ", searchObj.group(2))
print("searchObj.groups() : ", searchObj.groups())
else:
print("No search!!")

运行结果:

1
2
3
4
searchObj.group() :  Cats are smarter than dogs
searchObj.group(1) : Cats
searchObj.group(2) : smarter
searchObj.groups() : ('Cats', 'smarter')

3 re.match 和 re.search 的区别

re.match 只匹配字符串的开始,如果字符串开始不符合正则表达式(pattern),则匹配失败,函数返回 None ;而 re.search 匹配整个字符串,直到找到一个匹配。

例子:

1
2
3
4
5
6
7
8
9
10
import re

line = "Cats are smarter than dogs"
pattern1 = 'dogs'

matchObj = re.match(pattern1, line)
searchObj = re.search(pattern1, line)

print(matchObj)
print(searchObj)

运行结果:

1
2
None
<re.Match object; span=(22, 26), match='dogs'>

4 检索和替换

re 模块提供 re.sub 用于替换字符串中的匹配项

函数语法:

​ re.sub(pattern, repl, string, count=0, flags=0)

参数 描述
pattern 正则中的模式字符串
repl 替换的字符串,也可为一个函数
string 要被查找替换的原始字符串
count 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配

例子:

1
2
3
4
5
6
7
8
9
10
11
mport re

phone = "2004-959-559 # 这是一个国外电话号码"

# 删除字符串中的 Python注释
num = re.sub(r'#.*$', "", phone)
print("电话号码是: ", num)

# 删除非数字(-)的字符串
num = re.sub(r'\D', "", phone)
print("电话号码是 : ", num)

运行结果:

1
2
电话号码是:  2004-959-559
电话号码是 : 2004959559

4.1 repl参数可以是一个函数

例子:

1
2
3
4
5
6
7
8
9
10
11
12
import re

line = "www123eee4rrr56"


def r1(x):
value = int(x.group('value'))
return str(2 * value)


s = re.sub('(?P<value>\d+)', r1, line)
print(s)

运行结果:

1
www246eee8rrr112

4.2 re.compile函数

用于生成一个正则表达式,可供 match() 和 search() 使用。

语法格式:

​ re.compile(pattern[, flags])

参数 描述
pattern 一个字符串形式的正则表达式
flags 可选,标志,但愿你没忘记

例子 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
line = "www123eee4rrr56"

a = re.compile('\d+')

# match 部分
r1 = a.match(line)
print(r1)
r2 = a.match(line, 3) # 从第三位开始匹配
print(r2)
r3 = a.match(line, 4, 10) # 从第四位开始匹配
print(r3)
print(r3.start())
print(r3.end())

# search 部分
s1 = a.search(line)
print(s1)
s2 = a.search(line, 6)
print(s2)

运行结果:

1
2
3
4
5
6
7
None
<re.Match object; span=(3, 6), match='123'>
<re.Match object; span=(4, 6), match='23'>
4
6
<re.Match object; span=(3, 6), match='123'>
<re.Match object; span=(9, 10), match='4'>

Tips:

start() 方法和 end() 方法都是对于组group而言的,直接使用时,默认为 start(0) 和 end(0) ,即 group(0) 的起始位和终止位

例子 2:

1
2
3
4
5
6
7
8
9
10
11
12
13
import re

pattern1 = re.compile('([a-z]+) ([a-z]+)', re.I) # 标志位表示忽略大小写
line = "Hello World python gear"

m = pattern1.match(line)

print(m)
print(m.group())
print(m.span())

print(m.group(1))
print(m.span(1))

运行结果:

1
2
3
4
5
<re.Match object; span=(0, 11), match='Hello World'>
Hello World
(0, 11)
Hello
(0, 5)

4.3 findall

找到字符串匹配正则表达式的所有子串,返回一个列表。如果由多个匹配模式,则返回一个元组列表。

区别:match 和 search 是匹配一次,而 findall 是匹配所有。

语法格式:

​ findall(string[, pos[, endpos]])

​ re.findall(pattern, string[, pos[, endpos])

参数 解释
string 待匹配的字符串
pos 可选,字符串起始位置指定,默认为零
endpos 可选,字符串终止位置指定,默认为字符串的长度

例子1(返回列表):

1
2
3
4
5
6
7
8
9
10
11
import re

line = "www123eee4rrr56"

a = re.compile('\d+')

r1 = a.findall(line)
r2 = a.findall(line, 0, 14)

print(r1)
print(r2)
1
2
['123', '4', '56']
['123', '4', '5']

例子2(返回元组列表):

1
2
3
4
5
6
7
8
9
10
11
import re

line = "we have longitude = 121° and latitude = 30°"

a = re.compile('(\w+) = (\d+°)')

r1 = a.findall(line)
r2 = re.findall('(\w+) = (\d+)', line)

print(r1)
print(r2)
1
2
[('longitude', '121°'), ('latitude', '30°')]
[('longitude', '121'), ('latitude', '30')]

4.4 re.finditer

类似 findall,查找字符串中所有符合正则表达式的子串,并把它们作为一个迭代器返回。

语法格式:

​ re.finditer(pattern, string, fiags=0)

例子:

1
2
3
4
5
6
7
8
9
10
11
import re

line = "we have longitude = 121° and latitude = 30°"

a = re.compile('(\w+) = (\d+°)')

r1 = a.finditer(line)
print(r1)

for i in r1:
print(i.groups())
1
2
3
<callable_iterator object at 0x000002B69F1F93F0>
('longitude', '121°')
('latitude', '30°')

4.5 re.split

split 方法按匹配的子串将字符串分割后返回列表

语法格式:

​ re.split(pattern, string[, maxtype=0, flags=0])

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import re

line = 'unlimited blade works.'

patt0 = re.compile('\w+')
patt1 = re.compile('\W+')
patt2 = re.compile('(\W+)')

r0 = patt0.split(line)
r1 = patt1.split(line)
r2 = patt2.split(line)
r3 = re.split('\W+', line, 1)
r4 = re.split('(\W+)', line, 1)

print(r0)
print(r1)
print(r2)
print(r3)
print(r4)
1
2
3
4
5
['', ' ', ' ', '.']
['unlimited', 'blade', 'works', '']
['unlimited', ' ', 'blade', ' ', 'works', '.', '']
['unlimited', 'blade works.']
['unlimited', ' ', 'blade works.']

5 可选标志符 Flags

标志符 描述
re.I 使匹配对大小写不敏感
re.L 使本地化识别 (local-aware) 匹配
re.M 多行匹配,影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符
re.U 根据 Unicode 字符集解析字符,影响 \w,\W,\b ,\B
re.X 该标志通过给予你更灵活的形式以便你将正则表达式写得更容易被理解