有是一个安静的下午:
正则表达式
正则指引:python 语言使用正则表达式
能够多去思考 多找答案 从答案中找寻规律 得到属于你自己的感悟
知识点回顾
元字符:\d \w \s \n \t \b \W \D \S\ . ^ $ [] [^] () |
放在字符组中的元字符会现原形() [不能成对出现] . | + * -
号在中货号中有特殊的意义,需要转义 转义 \加需要转义的内容
量词 : 一共六个 + 表示1,+00 *表示 0,+00 ? 表示0|1
{n} 表示n次 {n,} 表示至少n次 {n,m}表示出现n-m次
贪婪匹配/惰性匹配:
默认是贪婪匹配 : 回溯 算法
改成惰性匹配 : 量词?
在范围内 尽量少的匹配
?(0.1) 尽量少的匹配就是匹配0次
转义符 :
在正则中有特殊意义的字符想让他们表示它本来的意义,就在这个字符前面
加上\
在正则中一些没有特殊意义的字符加上\ 就变成了有特殊意义的字符
简单小练习
1,匹配整数或者小数(包括正数和负数)
-?\d+(\.+)?
2、匹配年月日日期 格式2018-12-6
^[1-9]\d{3}-(1[0-2)|0?][1-9])-(3[01]|[12]\d])|0?[1-9]
- 匹配qq号
[1-9]\d{4,11}
4 . 十一位的电话号码
[1] [3-9]\d{9}
5.长度为8-10位的用户密码
\w{8,10}
- 匹配验证码 由四位数字字母组成
[0-9a-zA-Z]{4}
7匹配邮箱地址
^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$
8从类似的
<a>wahaha</a>
<b>banana</b>
<h1>qqxing</h1>
这样的字符串中,
1)匹配出wahaha,banana,qqxing内容。
有些时候你要匹配的内容和你不想匹配的内容符合的正则规则是一样的
\w{6}
>\w+<
2)匹配出a,b,h1这样的内容
<\w+>
9、1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))
1)从上面算式中匹配出内层没有其他小括号的表达式
\([^()]+\)
10、从类似9-1000/3+7/3*99/4*2998+10*568/14的表达式中匹配出从左到右第一个乘法或除法
\d+[*/]\d+
知识点 扩增
Re 模块
基础方法
在python中使用正则表达式的特点和问题
使用正则表达式的技巧
爬虫的例子
Random模块
Re模块
Import re 调用re模块
永远不要起一个py文件 的名字 和已经知道的模块同名
Regex 正则表达式
查找
Findall: 匹配所有 每一项都是列表中的每一个元素
import re
ret=re.findall("\d+","打打3213硕大的撒3231")
print(ret)
正则表达式,待匹配的字符串,flag
结果是这个
['3213', '3231']
Search : 只匹配从左到右的第一个,得到的不是直接的结果,
而是一个变量,通过这个变量的group方法来获取结果
如果没有匹配到,会返回none,使用group会报错
Print(ret)这个一个内存地址 通过 ret.group来获取真正的结果
ret=re.search("\d+","你看到我145的小熊122了么")
print(ret.group())
145
If ret:
Print(ret.group())
ret=re.match("\d+","44")
if ret:
print(ret.group())
Match 从头开始匹配,相当于search中的正则表达式加上一个^
^
字符串处理的扩展: 替换 切割
Split
s="alex|taibai|jinxing"
print(s.split("|"))
s1='alex83taibai40egon25a'
print(re.split("\d+",s1))
Sub 谁 旧的 新的 替换次数
ret=re.sub("\d+","H","nisdaldajsdka213213123131")
print(ret)
nisdaldajsdkaH
Subn 返回一个元祖,第二个元素是替换的次数
Ret=re.sunb 返回的数字 是在这个程序里 替换的次数
并不是说你标记几次就是几次是 他在可用的时候一红进行替换的次数
就是真实值,比如说你让他替换四次 字符串中只有三个可用替换的
那么他返回的就是3
Re模块的进阶 : 是时间\空间复杂度
Compile 节省你使用正则表达式解决问题的时间
编译 正则表达式 编译成 字节码
在多次使用的过程中 不会多次编译
一次就解决问题 会很方便 随调随用
ret=re.compile("\d+")
print(ret)
res=ret.findall("asdadsad123asdad3213")
print(res)
re.compile('\\d+')
['123', '3213']
Tinditer 节省你使用正则表达式解决问题的空间,也就是内存
ret=re.finditer("\d+","sadasda21313213sadada142141")
for i in ret:
print(i.group())
21313213
142141
这返回的是个内存地址 需要进行添加到group的形式才可以看到
Findall 返回列表 找到所有匹配项
Search 匹配 返回一个变量 通过group 去匹配到的第一个值,不匹配就返回None group 所有这个时候需要if 语句
Match 就相当于search 的正则表达式添加了一个^ 精准匹配
Split 返回列表 按照正则规则切割,默认匹配到的内容会被删掉
Sub/subn 替换 ,按照正则规则去须按照 要被替换掉的内容,subn返回
元祖,第二个值是替换的次数
Compile 便以一个正则表达式,用这个结果去search match findall finditer 节省时间
Finditer 返回一个迭代器,所有的结果都在这个迭代器中,需要通过循环+group的形式取值,能够节省内存
Inport re
s='<a>wahaha</a>'
ret=re.search("<(\w+)>(\w+)</(\w+)>",s)
print(ret.group(1))
print(ret.group(2))
print(ret.group(3))
a
wahaha
a
取消分组优先(?:正则表达式)
R
关于分组,
对于正则表达式来说 有些时候我哦们需要进行分组,
来整体约束某一字符出现的次数
(\.[\w]+)?
对于python语言来说 分组可以帮助你更好更精准的找到你真正需要的内容
<(\w+)>(\w)</(\w+)>
Split
ret=re.split('\d+','alxe32asda414115aaadsa23asdada')
print(ret)
ret1=re.split('(\d+)','alxe32asda414115aaadsa23asdada')
print(ret1)
['alxe', 'asda', 'aaadsa', 'asdada']
['alxe', '32', 'asda', '414115', 'aaadsa', '23', 'asdada']
用括号把需要的东西括起来 split 会默认显示被切割掉的东西
Python 和正则表达式 之间的特殊约定
分组命名(?P<这个组的名字>正则表达式)
import re
s = '<a>wahaha</a>'
ret=re.search('>(?P<cont>\w+)<',s)
print(ret.group(0))
ret2 = re.search('>(?P<con>\w+)<',s)
print(ret2.group("con"))
s='<a>wahaha</a>'
pattern="<(\w+)>(\w+)</(\w+)>"
ret=re.search(pattern,s)
print(ret.group(1)== ret.group(3))
使用前面的分组 要求使用这个名字的分组和前面同名分组中的内容匹配的必须一致
pattern='<(?P<tab>\w+)>(\w+)</(?P=tab)>'
ret=re.search(pattern,s)
print(ret)
ret=re.findall(r"\d+\.\d+|\d+","1-2*(60+(-40.35/5)-(-4*3))")
print(ret)
ret=re.findall(r"\d+\.\d+|(\d+)","1-2*(60+(-40.35/5)-(-4*3))")
print(ret)
ret=re.findall(r"\d+","1-2*(60+(-40.35/5)-(-4*3))")
print(ret)
ret1=re.findall(r"\d+\.\d+|\d+","1-2*(60+(-40.35/5)-(-4*3))")
print(ret1)
ret2=re.findall(r"\d+\.\d+|(\d+)","1-2*(60+(-40.35/5)-(-4*3))")
ret2.remove('')
print(ret2)
s = '|1132|56564|'
print(s.split("|"))
['1', '2', '60', '40.35', '5', '4', '3']
['1', '2', '60', '', '5', '4', '3']
['1', '2', '60', '40', '35', '5', '4', '3']
['1', '2', '60', '40.35', '5', '4', '3']
['1', '2', '60', '5', '4', '3']
['', '1132', '56564', '']
简单爬虫
Import
From
import re
from urllib.request import urlopen
def getPage(url): # 获取网页的字符串
response = urlopen(url)
return response.read().decode('utf-8')
def parsePage(s):
ret = com.finditer(s) # 从s这个网页源码中 找到所有符合com正则表达式规则的内容 并且以迭代器的形式返回
for i in ret:
yield {
"id": i.group("id"),
"title": i.group("title"),
"rating_num": i.group("rating_num"),
"comment_num": i.group("comment_num"),
}
def main(num): # 0 25 50 # 这个函数执行10次,每次爬取一页的内容
url = 'https://movie.douban.com/top250?start=%s&filter=' % num
response_html = getPage(url) # response_html就是这个url对应的html代码 就是 str
ret = parsePage(response_html) # ret是一个生成器
print(ret)
f = open("move_info7", "a", encoding="utf8")
for obj in ret:
print(obj)
data = str(obj)
f.write(data + "\n")
f.close()
com = re.compile(
'<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>'
'.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>', re.S)
count = 0
for i in range(10):
main(count)
count += 25