python--re模块, 正则表达式

正则表达式是对字符串操作的一种逻辑公式.我们一般使用正则表达式对字符串进行匹配和过滤.使用正则的优缺点:

有点:灵活,功能性强,逻辑性强

缺点: 上手难.一旦上手,会爱上这个东西

工具: 各大文本编辑器一般都由正则匹配功能. 我们可以去http://tool.chinaz.com/regex/ 在线使用工具进行测试

 

1. 正则表达式,匹配字符串

元字符

字符组很简单用[]括起来,在[]中出现的内容会被匹配,例如:[abc] 匹配a或b或c

如果字符组中的内容过多还可以使用-,

[a-zA-Z0-9] 匹配的是字母a-z或A-z或0-9中的任意一个

 

.      匹配除换行符以外的任意字符
\w     匹配字母或数字或下划线
\s     匹配任意的空白符
\d     匹配数字
\n     匹配一个换行符
\t     匹配一个制表符
\b     匹配一个单词的边界
^      匹配字符串的开始
$      匹配字符串的结尾
\W     匹配非字母或数字或下划线
\D     匹配非数字
\S     匹配非空白符
a|b    匹配字符a或字符b
()     匹配括号内的表达式,也表示一个组
[...]  匹配字符组中的字符
[^...] 匹配除了字符组中字符的所有字符

  

量词

一次性匹配多个字符就要用到量词

*       重复0次或更多次
+       重复1次或更多次
?       重复0次或1次
{n}     重复n次
{n,}    重复n次或更多次
{n,m}   重复n到m次

  

惰性匹配和贪婪匹配

在量词中的 * , +, {} 都属于贪婪匹配,就是尽可能多的匹配到结果 

.*?     尽可能少的匹配,表示惰性匹配

str: <div>胡辣汤</div>
reg: <.*>
结果: <div>胡辣汤</div>

str: <div>胡辣汤</div>
reg: <.*?>
结果:
<div>
</div>

str: <div>胡辣汤</div>
reg: <(div|/div*)?>
结果:
<div>
</div>

  

惰性匹配和贪婪匹配

贪婪
.* 尽可能多的匹配
.+

惰性:
.*?哈哈 尽可能少的匹配

  

分组:

使用括号()进行分组

 

转义:

在正则表达式中,有很多特殊意义的元字符,如果要在正则中匹配正常的\n而不是"换行符"就需要对"\"进行转义,太麻烦了,

所以我们就用到了r'\n'这个概念,为了打出 str ->' \n' ,此时的正则是r'\\n'就可以了

 

2. re 模块

在python中使用正则. re

(?P<name>正则)  用的时候直接 group("name")就可以了

1. search() 搜索. 搜索到第一个结果返回

search和match的区别:  search查找. 找到了结果就返回. match. 从头开始匹配.

r = re.search("\d+","电话号码123456789")
print(r)  # <_sre.SRE_Match object; span=(4, 13), match='123456789'>
print(r.group())  # 123456789

2. match() 匹配. 收到一个结果返回. 只能从字符串开开始匹配

r = re.match("\d+","电话号码123456789")
print(r)
print(r.group())

结果
<_sre.SRE_Match object; span=(0, 3), match='123'>
123

  所以显示出match是从字符串开始进行匹配

r = re.match("\d+","12312电话号码123456789")
print(r)
print(r.group())

结果
<_sre.SRE_Match object; span=(0, 5), match='12312'>
12312

3. findall() 查找所有匹配结果

r = re.findall("\d+","电话号码123456789")
print(r)  # ['123456789']

4. finditer() 返回迭代器.

result = re.finditer(r"姓名:(?P<name>.*?), 爱好:(?P<hobby>.*?),", "姓名:小名, 爱好:女,")
for el in result:
    print(el.group("name"), el.group("hobby"))

结果
<callable_iterator object at 0x000002044EBDF2E8>
<callable_iterator object at 0x000002044EBDF2E8>
小名 女

5. compile() 编译

reg = re.compile(r'\d+')  # 加载了一段正则
lst = reg.findall("呵呵, 笨蛋才不去134呢.他要去1123了")
print(lst)

结果
['134', '1123']

6. group("name") 获取数据

result = re.finditer(r"姓名:(?P<name>.*?), 爱好:(?P<hobby>.*?),", "姓名:小名, 爱好:女,")
for el in result:
    print(el.group("name"), el.group("hobby"))

结果
<callable_iterator object at 0x000002044EBDF2E8>
<callable_iterator object at 0x000002044EBDF2E8>
小名 女

7.  re.S  去掉 . 的换行

在网页源码中有许多空白, re.S就是为了去掉这些空白

# 爬取电影天堂
from urllib.request import urlopen

content = urlopen("https://www.dytt8.net/html/gndy/dyzz/20181219/57954.html").read().decode("gbk")
# print(content)

reg = r'<div id="Zoom">.*?片  名(?P<name>.*?)<br />◎年  代(?P<years>.*?)<br />.*?◎上映日期(?P<date>.*?)<br />'+ \
'.*?◎主  演(?P<main>.*?)◎简  介.*?<td style="WORD-WRAP: break-word" bgcolor="#fdfddf"><a href="(?P<download>.*?)">'

it = re.finditer(reg, content, re.S) # re.S 去掉.里面的\n

for el in it:
    print(el.group("name"))
    print(el.group("years"))
    print(el.group("date"))
    print(el.group("main").replace("<br />      ", ", "))
    print(el.group("download"))

8. (?:) 把表达式从python中的正则分组变为正则表达式中的分组

lst = re.findall(r"a(?:\d+)c", "a123456c") # 把括号python中的分组变成了原来正则表达式中的分组
print(lst)

lst = re.findall(r"a(\d+)c", "a123456c") # 把括号python中的分组变成了原来正则表达式中的分组
print(lst)

结果
['a123456c']
['123456']

  

 3. 其他操作

1.sub,替换目标字符串

ret = re.sub(r'\d+','__???__',"mike1446inn9988oeoeujt") # 把字符串中的数字替换成__???__
print(ret)  

结果
# mike__???__inn__???__oeoeujt

2.subn,替换目标字符串并返回为元组,并对替换的次数计数

ret = re.subn(r'\d+','__???__',"mike1446inn9988oeoeujt")
print(ret)

结果
('mike__???__inn__???__oeoeujt', 2)

3.正则中的split()

ret = re.split('[ab]','qqqqeafiefubdkksd')
print(ret)

结果
['qqqqe', 'fiefu', 'dkksd']

  注意事项:在匹配部分加上()之后所切出的结果是不同的

爬虫重点:

obj = re.compile(r'(?P<id>\d+)(?P<name>e+)') # 从正则表达式匹配的内容每个组起名字
ret = obj.search('abc123eeee') # 搜索
print(ret.group()) # 结果: 123eeee
print(ret.group("id")) # 结果: 123 # 获取id组的内容
print(ret.group("name")) # 结果: eeee # 获取name组的内容

 

 

在匹配部分没有加()的话,不保留匹配部分 

ret = re.split("\d+","eklfj3fe4efji")
print(ret)  # ['eklfj', 'fe', 'efji']

 

在匹配部分加了()的话,保留匹配部分

ret1 = re.split("(\d+)","eklfj3fe4efji")
print(ret1)  #  ['eklfj', '3', 'fe', '4', 'efji']

  

lst = re.findall(r"a(?:\d+)c", "a123456c") # 把括号python中的分组变成了原来正则表达式中的分组

 

 

 

 

 

 

posted @ 2018-12-28 21:55  robertx  阅读(212)  评论(0编辑  收藏  举报