全民一起玩Python提高篇第九课:字符串与正则表达式(下 )

环视

VBA版环视
https://editor.csdn.net/md/?articleId=104145450
给一段文本

产品A01的序列号是35-3-401,B35序列号是25-7-330-7-2568,产品C09的序列号是:01-48-401-32。

捕获类似35-3-401结构的,第一个数字之后的所有数字
用两层正则表达式来破解

import re
s='产品A01的序列号是35-3-401,B35序列号是25-7-330-7-2568,产品C09的序列号是:01-48-401-32。'
a=re.findall('\d+(?:-\d+)+',s)
#\d+匹配数字,(-\d+)+后面的结构作为一组反复出现  ?:改为非捕获组
#如果直接写成\d+(?:-(\d+))+   那么捕获组只会捕获最后一个符合要求的表达
#写几个圆括号,就只有几个捕获组
for i in a:
    #将完整的字符串拿来继续分解
    b=re.findall('-(\d+)',i)
    #打印每一组字符串第一个数字之后的所有数字
    print(b)

输出结果
[‘3’, ‘401’]
[‘7’, ‘330’, ‘7’, ‘2568’]
[‘48’, ‘401’, ‘32’]

另一段文本

《2018年北京市社会建设和民政事业发展统计公报》显示,2014年2018年,结婚登记对数从170027对降至137818对,而离婚登记对数从56192对增长至66616对。2014年2018年连续5年的离结比分别为:33.05%、43.97%、58.71%、48.18%、48.34%。
北京市民政局官微文章曾指出,在各省离婚结婚比统计中,黑龙江省的离婚结婚比高达63%。这意味着有100对夫妻结婚,就有63对夫妻离婚,也就是0.63的离 结比。除了黑龙江,天津、吉林、辽宁、重庆的离结比也纷纷超过5成,上海、北京则紧随其后,分别为49%、48%。

找出所有的百分数

\d+\.\d+%

在这里插入图片描述
如果不想要百分号本身,加一个捕获组就可以

(
\d+\.\d+)%

使用环视,能够满足所需要的字符串,以XX开头或者结尾XX,或者左边、右边是XX,但匹配结果不要XX

look around

顺序肯定型--(?=后面必须是什么文字)
顺序否定型--(?!后面禁止是什么文字)
逆序肯定型--(?<=前面必须是什么文字)
逆序否定型--(?<!前面禁止是什么文字)

找所有整数部分
前面不能是小数点,数字,不然会读取到,后面也不能是

(?<![.\d])\d+(?![.\d])(?=%)

在这里插入图片描述
逆序环视必须定量长度,不能用+

题目:求和

本作业改编自真实工程预算案例。请首先编写一个正则表达式,能够将下面这行文本中的工程数字,即方括号之外的 137.059、15.591、8.148 三个数字全部提取出来:
137.059【雨水管至检查井】+15.591【000】+8.148【007】
在完成上述任务后, 请下载Excel文件 工程概算表格 。该文件中B列每一行都是上面形式的文本,但具体数字个数不同。请编写一个Python程序,使用上一任务得到的正则式,自动将每一行的工程数字提取出来并计算总和(保留小数点后三位数字),再将总和存入C列。

import re
import xlwings as xw
app=xw.App()
wb=app.books.open('E:\拷贝过来的文件\全民一起玩Python\MyProject\Test2\提高篇第三十课\第三十课练习.xlsx')
ws=wb.sheets[0]
a=ws.range('B2:B67').value
x=2
for i in a:
    s=re.findall('\d+\.\d+',i)
    sum=0
    for j in s:
        sum=sum+float(j)
        ws.range('C'+str(x)).value=sum
    x += 1
wb.save()
wb.close()
app.quit()

在这里插入图片描述

题目:匹配邮箱

某同学想编写一个python邮件群发程序,自动向所有好友的QQ邮箱发送邮件。作为测试,他先写了下面的代码,希望用户输入一个QQ号码(或者从邮件列表文件中读入一个QQ号码)后,自动将模板字符串"xxxxxxxxx@qq.com" (即变量 s )替换为类似 “822344332@qq.com” 的形式。请补充该程序使之能够完成上述任务。

import re
qq = input('请输入对方Q号')
r = re.sub(r'(\d+)',r'QQ邮箱:\1@qq.com',qq)
#加上r防止转义
print(r)
#或者是提前写好一个模板
s = 'xxxxxxxxx@qq.com'
qq = input('请输入对方Q号')
r = re.sub( r'x+', qq, s )
print( r )

某人将好友的姓名、手机号和邮箱地址都以下列格式记录在电脑中: ‘Ada13500834532822344332@qq.com’,其中各字段之间没有空格,手机确定为11位数字。现在为了让记录更加直观, 需要将它们拆开,并在名字、手机号和邮箱前面分别加上文字说明,

import re
s='Ada13500834532822344332@qq.com'
a=re.sub(r'(\w+)(\d{11})(.+)',r'姓名:\1 手机:\2 邮箱:\3',s)
print(a)

注意,这里的替换并不是把找到的东西替换成其他的,而是找到的东西保留,其他地方进行变化

读取word

先要安装一手第三方模块
python-docx
word和Excel对象可以先做一手对比

docx.Documentxlwings.workbook
docx.paragraphxlwings.sheet
docx.Paragraphsxlwings.sheets
docx.Paragraphs[0].textxlwings.sheets[0].value

方便给多个朋友批量发送邮件,某人将多个朋友的身份信息存储到了一个 word文档 中。现在请编写一个程序,将其中每个人的信息从文档中读取出来并保存到一个列表,。

import docx
import re
doc=docx.Document(r'E:\拷贝过来的文件\全民一起玩Python\MyProject\Test2\提高篇第三十一课\读写word.docx')
#p=doc.paragraphs[0]
res_li = []
for p in doc.paragraphs:
    res_li.append(p.text.replace(u'\xa0', '' ))
    #处理掉换行符和回车符之类的
print(res_li)

word批量替换任务

在文件夹中有三个Word文件(请下载 压缩文件 ),内容都是格式相同的好友名单。请编写 Python 程序,将三份文档中每一行的后面都加入 “年龄: 保密” 几个字。

import docx
import os
root='E:\拷贝过来的文件\全民一起玩Python\MyProject\Test2\提高篇第三十一课\python02_31_02'
#保存根目录
file_name=os.listdir(root)
#读取所有文件名
for f in file_name:
    doc=docx.Document(f'{root}/{f}')
    #设置doc
    for p in doc.paragraphs:
        p.text=p.text+'年龄:保密'
        #每段后加上一句
    doc.save(f'{root}/{f}')

反向引用

happy to see you
针对上面这种文本
想要找到
happy中的pp,see里面的ee
即捕捉同前一样式一样的格式

(\w)\1

可以用\w匹配字母,把他做一个捕获组,然后再后面引用这个捕获组
在这里插入图片描述
如果想找回文单词
可以写

\b(\w)\w+\1\b

两个斜杠b用来找出一个单词的始末位置,然后斜杠w用来装开头字母
斜杠1用来找末尾和开头相同的,中间斜杠w加,匹配任意多个字母
在这里插入图片描述

re的功能函数

findall函数查找所有符合正则式的字符串
sub函数执行正则表达式替换功能
search函数查找第一个符合正则式的字符串
match函数检查字符串前端是否符合正则式
compile函数预编译正则式以提高效率

search找到的是一个match对象
match也是返回一个match对象
都只是返回第一个结果
match必须从头开始匹配,如果开头不符合要求,那就不行
可以用来判断变量命名,比如开头必须是字母数字下划线,可以用这个判断

match的优越性还体现在了
只返回第一个符合要求的子串,但Match.group()可以获取完整结果及所有捕获组

Match.group(0)完整匹配结果
Match.group(1)返回第一个捕获组的内容

findall返回所有符合条件的,但若有捕获组,只返回捕获组

import re
s='25-37-8888,21-05-7777'
a=re.findall(r'(\d+)-(\d+)-(\d+)',s)
print(a)
b=re.search(r'(\d+)-(\d+)-(\d+)',s)
print(b.group(0))
print(b.group(1))

输出结果

[('25', '37', '8888'), ('21', '05', '7777')]
25-37-8888
25

想要结合两者的优点,使用finditer
找到所有符合条件的子串,并将每一个子串分别包装为一个Match对象,再放入迭代器返回

import re
s='25-37-8888,21-05-7777'
c=re.finditer(r'(\d+)-(\d+)-(\d+)',s)
for i in c:
    print(i.group(0),i.groups())
25-37-8888 ('25', '37', '8888')
21-05-7777 ('21', '05', '7777')

也可以用compile编译一个正则表达式对象出来

import re
s='25-37-8888,21-05-7777'
a=re.findall(r'(\d+)-(\d+)-(\d+)',s)
print(a)
p=re.compile(r'(\d+)-(\d+)-(\d+)')
#将p做成一个正则表达式对象,re的属性直接调用就可以
a=p.findall(s)
print(a)
b=re.search(r'(\d+)-(\d+)-(\d+)',s)
print(b)
b=p.search(s)
print(b)

两组情况完全等价
定义为对象后可以更加利于重用。

题目:预编译练习

请先下载 网页源代码示例文件,其内容是某代理服务器网站上采集到的免费代理数据。然后请编写Python程序,从中提取出代理地址,例如: “163.204.240.10”。由于实际应用中面对的数据量会很大,所以要求使用正则预编译提高效率,并将最后的结果打印在屏幕上。

import re
a='''<tr><td>163.204.240.10</td>
 <td>9999</td>
 <td>高匿</td>
 <td>HTTP</td>
 <td>广东省汕尾市 联通</td>
 <td>1秒</td>
 <td>2020-02-17 23:31:01</td>
</tr>
<tr><td>49.76.193.237</td>
 <td>9999</td>
 <td>高匿</td>
 <td>HTTP</td>
 <td>江苏无锡</td>
 <td>0.173秒</td>
 <td>2020-02-17 23:21:00</td>
</tr>
<tr><td>114.224.28.154</td>
 <td>9999</td>
 <td>高匿</td>
 <td>HTTP</td>
 <td>江苏无锡</td>
 <td>0.187秒</td>
 <td>2020-02-17 23:21:00</td>
</tr>
'''
p=re.compile(r'<tr><td>(.*?)</td>')
#因为每行分的很清楚,所以先选定以<tr>打头
#然后选<td></td>标签内的内容
s=p.findall(a)
print(s)

下面是一些个人信息,其中某些位置的姓名存在重复。请在Regex101中使用正则式对姓名进行替换去重。

姓名:张三 联系方式538233287张三
姓名:李四 电话:98835522
姓名:王五 电话:王五87323003
姓名:赵六 请电话联系赵六88332233
姓名:田七 联系方式:78332233
姓名:萧十一郎 联系方式38775322萧十一郎

(姓名:(.*?)\s(.*))\2

在这里插入图片描述

题目:去重复

  1. 表格中某些行的姓名文本存在重复(比如MadgeMadge),并且最多只重复一次。请使用正则式的反向引用功能进行去重操作(比如改为Madge)。
  2. 通过正则式提取所有以137开头,尾号是2的手机号,将它们打印出来。
import re
import xlwings as xw
app=xw.App()
wb=app.books.open(r'E:\拷贝过来的文件\全民一起玩Python\MyProject\Test2\提高篇第三十二课\第三十二课测试.xlsx')
ws=wb.sheets[0]
name=ws.range('A2:A8').value
result=[]
p = re.compile(r'((\w)+?)\1')
for i in name:
    a = p.sub(r'\1', i)
    result.append(a)
ws.range('D2:D8').options(transpose=True).value=result

num=ws.range('C2:C8').value
p = re.compile(r'(137.+2)')
result2=[]
for i in num:
    b=p.findall(i)
    if b:
        print(b)
wb.save()
wb.close()
app.quit()

输出结果
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值