当获取到页面的内容之后,怎么样提取想要的文字呢?正则表达式就是一个很好用的工具。在很多编程语言里面都有正则表达式的概念。正则表达式比较常见的是对字符串操作,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。除了提取文字外,比较常见的还有判断是不是email,是不是手机号等功能。
re模块
Python使用\
作为转义字符,匹配的时候很容易少写反斜杠等问题。Python中re 模块提供了正则表达式的支持,可以很好的解决这个问题。
举个例子:
不使用re
s = 'lzc\\dev' # Python的字符串
# 对应的正则表达式字符串变成:
# 'lzc\dev'
使用re模块
s = r'lzc\dev' # Python的字符串
# 对应的正则表达式字符串是不变的
# 'lzc\dev'
主要函数:
函数名 | 语法 | 描述 |
---|---|---|
compile | re.compile(string[,flag]) | 用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用 |
match | re.match(pattern, string[, flags]) | 从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话(也可以指定起始位置),match()就返回none |
search | re.search(pattern, string[, flags]) | 扫描整个字符串并返回第一个成功的匹配 |
split | re.split(pattern, string[, maxsplit]) | 按照能够匹配的子串将字符串分割后返回列表 |
findall | re.findall(pattern, string[, flags]) | 在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表 |
finditer | re.finditer(pattern, string[, flags]) | 在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回 |
sub | re.sub(pattern, repl, string[, count]) | 用于替换字符串中的匹配项 |
subn | re.subn(pattern, repl, string[, count]) | 跟 sub 方法的行为类似,也用于替换 |
compile
pattern=re.compile(pattern[, flag])
compile函数用来生成一个pattern对象,pattern 是一个字符串形式的正则表达式,flag 是一个可选参数,表示匹配模式,比如re.I
表示忽略大小写,还有比较常用的re.S
表示. 并且包括换行符在内的任意字符(. 不包括换行符)。通常 pattern要跟re模块的方法结合使用。
import re
pattern = re.compile(r'\d+') # 用于匹配至少一个数字
re.match
re.match(pattern, string[, flags])
结合pattern使用,我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。pattern是要匹配的正则表达式,string是要匹配的字符串,flags是标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等
#!/usr/bin/python
#coding:utf-8
import re
pattern1 = re.compile(r'\d+') # 用于匹配至少一个数字
pattern2 = re.compile(r'([a-z])', re.I) # re.I 表示忽略大小写
m1 = pattern1.match('lzc123')
m2 = pattern2.match('lzc123')
print m1 # None
print m2.groups() # ('l',)
m3 = pattern1.match('1lzc23')
m4 = pattern1.match('123lzc')
print m3 # <_sre.SRE_Match object at 0x104801ac0> (返回一个 Match 对象)
print m3.group() # 1
print m4.group() # 123
re.search
re.search(pattern, string, flags=0)
用法跟match差不多。re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
import re
matchObj = re.match(r'lzc', 'Is lzc handsome?', re.M|re.I)
if matchObj:
print matchObj.group()
else:
print 'no match'
# no match
searchObj = re.search(r'lzc', 'Is lzc handsome?', re.M|re.I)
if searchObj:
print searchObj.group()
else:
print 'no search'
# lzc
re.split
re.split(pattern, string[, maxsplit=0, flags=0])
split 方法按照能够匹配的子串将字符串分割后返回列表。这里的maxsplit表示分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。
import re
r = re.split('(\W+)', 'lzc,is,handsome.')
r2 = re.split(r'is', 'lzcishandsome')
print r # ['lzc', ',', 'is', ',', 'handsome', '.', '']
print r2 # ['lzc', 'handsome']
findall
findall(string[, pos[, endpos]])
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。string 是要匹配的字符串,pos :是可选参数,指定字符串的起始位置,默认为 0。endpos :也是可选参数,指定字符串的结束位置,默认为字符串的长度。注意这里和match、search有区别:match 和 search 是匹配一次 ,findall 匹配所有。
import re
pattern = re.compile(r'\d+') # 查找数字
result1 = pattern.findall('lzc1 is2 very3 handsome')
result2 = pattern.findall('lzc11isvery22handsome333', 0, 12)
print(result1) # ['1', '2', '3']
print(result2) # ['11', '2']
finditer
re.finditer(pattern, string, flags=0)
这个用法和 findall 差不多,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。这个平时用的不太多
import re
it = re.finditer(r"\d+","1lzc23is45handsome6666")
for match in it:
print (match.group())
# 1
# 23
# 45
# 6666
sub
re.sub(pattern, repl, string, count=0, flags=0)
repl表示替换的字符串,也可为一个函数,string是要被查找替换的原始字符串,count是模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
import re
string = "lzc-number111 # 这是我的名字"
# 删除字符串中的注释
str1 = re.sub(r'#.*$', "", string)
print str1 # lzc-number111
# 删除非数字的字符串
str2 = re.sub(r'\D', "", string)
print str2 # 111
subn
subn(repl, string[, count])
subn 方法跟 sub 方法的用法差不多,也用于替换。
import re
def add(m):
# Convert.
v = int(m.group(0))
# Add 2.
return str(v + 1)
# Call re.subn.
result = re.subn("\d+", add, "1 2 3 4 5")
print("Result string:", result[0]) # ('Result string:', '2 3 4 5 6')
print("Number of substitutions:", result[1]) # ('Number of substitutions:', 5)
贪婪模式与非贪婪模式
从字面上就可以猜到:贪婪模式,就是在整个表达式匹配成功的前提下,尽可能多的匹配,有多少就匹配多少。而非贪婪模式,就是在整个表达式匹配成功的前提下,尽可能少的匹配,就是找到一个想要的就行了,至于还有没有就不管了。Python中默认是贪婪模式的。如果想要非贪婪模式,则要用到?
。看一个常见的用法(.*?)
(.*)
: 代表匹配除换行符之外的所有字符。
(.*?)
: 其中?
代表非贪婪模式,也就是说只匹配符合条件的最少字符
举个例子:
import re
content = 'lzc<div>is</div>handsome<div>test</div>haha'
pattern1 = re.compile(r'<div>(.*)</div>')
result1 = pattern1.findall(content)
print result1 # ['is</div>handsome<div>test']
pattern2 = re.compile(r'<div>(.*?)</div>')
result2 = pattern2.findall(content)
print result2 # ['is', 'test']
小结
正则表达式非常强大,多多练习,多看资料才能用好它,发挥它真正的实力。