目录
正则表达式
- 基本概念
- 元字符
- re.fingall正则寻找
- re.sub正则替换
- re.其他函数
- group分组
- 小结
- JSON文件
一、正则表达式
(四) re.sub
正则替换
在re模块下,只有re.findall()
这一方法吗?
不是,还有用于替换的re.sub
方法。
1.例题
(1)将字符串'PythonC#JavaPHP'
中的C#
替换成GO
?
import re
language = 'PythonC#JavaPHP' #1个C#
r = re.sub('C#','GO',language) #将第一个参数,替换成第二个参数
print(r)
-->
PythonGOJavaPHP
(2)将字符串'PythonC#JavaC#PHPC#'
中的C#
全部替换成GO
?(有多个C#)
import re
language = 'PythonC#JavaC#PHPC#' #3个C#
r = re.sub('C#','GO',language)
print(r)
-->
PythonGOJavaGOPHPGO
(3)如果只想将字符串'PythonC#JavaC#PHPC#'
中的第一个C#
替换成GO
呢?
指定替换的最大次数
如果什么都不填写,就默认是0,全部替换
import re
language = 'PythonC#JavaC#PHPC#' #3个C#
r = re.sub('C#','GO',language,1) #将第一个C#进行替换
print(r)
-->
PythonGOJavaC#PHPC#
2.replace内置函数
系统内置函数replace()
是正则表达式re.sub()
方法的简化版,常用于常规替换。re.sub()
则用于超强的复杂替换。
将字符串'PythonC#\nJavaPHPC#'
中的C#
替换成GO
?
language = 'PythonC#\nJavaPHPC#' #2个C#
language.replace('C#','GO') #将第一个参数,替换成第二个参数
print(language)
-->
PythonC#\nJavaPHPC# #没有替换?因为字符串str是不可变的数据类型
要想替换成功,就必须将新生成的字符串,用一个其他的新变量来接受结果
改正
language = 'PythonC#\nJavaPHPC#' #2个C#
language = language.replace('C#','GO') #将第一个参数,替换成第二个参数
print(language)
-->
PythonGO\nJavaPHPGO #
3.re.sub()
的强大用法
第二个参数可以是函数
(1)用于替换的函数convert(value)
的用法
import re
language = 'PythonC#JavaC#PHPC#'
def convert(value): #value 是中间值 #先定义,后调用
pass #函数里只有占位符,什么都没有,所以替换成空
r = re.sub('C#',convert,language) #convert 是函数,不再是常量的字符串,不用加引号
print(r)
-->
PythonJavaPHP
(2)例题
将字符串'PythonC#JavaC#PHPC#'
中,的C#
替换成!!C#!!
,以将其凸显出来?
import re
language = 'PythonC#JavaC#PHPC#'
def convert(value): #value 是中间值
return '!!' + value + '!!'
r = re.sub('C#',convert,language)
print(r)
-->
error ❌ #难道value,不是普通的字符串?
打印出value
,看看是什么?
import re
language = 'PythonC#JavaC#PHPC#'
def convert(value): #value不是简单的字符串,由结果可知,而是一个对象
print(value)
r = re.sub('C#',convert,language) #因为有3个C#,所以convert被执行了3次
print(r)
-->
<re.Match object; span=(6, 8), match='C#'> #额外信息:匹配对象在原字符串的位置
#误区:匹配对象出现在6、7、8三个位置 -->应该是C#前有6个字符,自己占了7、8两位
<re.Match object; span=(13, 15), match='C#'>
<re.Match object; span=(18, 20), match='C#'>
PythonJavaPHP #匹配结果
改正
import re
language = 'PythonC#JavaC#PHPC#'
def convert(value):
matched = value.group() #调用value的group方法,将具体的字符从对象中拿出来
return '!!' + matched + '!!'
r = re.sub('C#',convert,language)
print(r)
-->
Python!!C#!!Java!!C#!!PHP!!C#!!
(3)函数传递到sub中的用途
可以根据不同的匹配结果,做出不同的替换操作。
例题
找出字符串'A8C3721D86'
中所有的数字,把大于6的,替换成数字9;把小于6的,替换成数字0?
import re
s = 'A8C3721D86'
def convert(value):
matched = value.group()
if matched >= 6: #左边是字符串str,右边是整型int,之间不能做比较运算?
return 9
else:
return 0
r = re.sub('\d',convert,s) #注意:这是字符串'\d',不是纯数字\d
print(r)
-->
error ❌
'>=' not supported between instances of 'str' and 'int'
以上的错误,是因为比较运算符的两边数据类型的问题。改正:
import re
s = 'A8C3721D86'
def convert(value):
matched = value.group()
if int(matched) >= 6: #int与int做比较运算
return 9 #返回的结果9是要进入字符串中的,但他却是int
else:
return 0
r = re.sub('\d',convert,s)
print(r)
-->
error ❌
TypeError: sequence item 1: expected str instance, int found
以上的错误,是因为return返回值的数据类型与原字符串的数据类型的问题。改正:
import re
s = 'A8C3721D86'
def convert(value):
matched = value.group()
if int(matched) >= 6: #int与int做比较运算
return '9' #返回的结果9是要进入字符串中的,但他却是int
else:
return '0'
r = re.sub('\d',convert,s)
print(r)
-->
A9C0900D99
七月老师:
上面体现了软件设计的一个经典思想:
一个函数,可以接受另一个函数作为参数
我:正则表达式sub的设计方-------留一个接口给使用方
你:使用方------具体怎么处理,交给使用方
思考题
for循环与sub正则在替换方面的对比
单一的字符匹配,for循环也可以做到。
但多个字符的匹配呢?复杂模糊的匹配呢?显然此时,sub正则更好用
例如:
将字符串'A8C3721D86'
中的单个数字剔除,把两位数字作为一个整数做判断:大于50的,替换成数字100,小于50的,替换成数字0 ?
(五)re模块中的其他函数
re.match
re.search
特点:
- 两者功能都是查找,但是只匹配一次。
- 功能虽然比re.foundall强大,但是不如后者直白、好用。
1.re.match的用法
import re
s = 'A83C72D1D8E67'
r = re.match('\d',s) #从首位置开始寻找,A不是数字,结束
print(r)
-->
None #空值
2.re.search的用法
import re
s = 'A83C72D1D8E67'
r = re.search('\d',s) #搜索整个字符串,直到找到第一个结果
print(r)
-->
<re.Match object; span=(1, 2), match='8'> #结果是'8',位置在第二
#是match对象
(六)group的用法
之前,讲过分组的概念:用小括号将元字符括起来,作为一组。
如何将上面的对象中的具体的结果表示出来呢?
调用group 方法
本质:获取分组的匹配
1.例题:
把字符串life is short,i use python.
中,life
与python
中间的所有元素提取出来?(用search)
因为中间的元素既有字母,又有空格,所以不能用w\*
。
import re
s = 'life is short,i use python.'
r = re.search('life.*python',s)
print(r.group()) #是r.group(0)的默认
-->
life is short,i use python #完整的结果匹配出来了,但是还包括两边的标签
import re
s = 'life is short,i use python.'
r = re.search('life(.*)python',s)
#剔除两边的标签:把中间模糊匹配的元字符,当作一个分组(.*)
print(r.group(0))
-->
life is short,i use python #也完整的匹配出来了:元字符小括号没起作用?
由上可知,group(0)是特殊的情况,记录的永远是正则表达式的完整匹配结果。
要想表示完整匹配结果内部的某个分组的取值,就必须指定组号或从第1组访问
import re
s = 'life is short,i use python.'
r = re.search('life(.*)python',s)
print(r.group(1)) #显得麻烦
-->
is short,i use
比较findall()
的写法
import re
s = 'life is short,i use python.'
r = re.findall('life(.*)python',s)
print(r)
-->
[' is short,i use '] #简洁、直白
小结:
既然re.findall
这么好用,为什么还要讲re.search
呢?
因为后者有个功能是可以附带匹配结果的位置信息,有时会用到。
2.group分组有多个的情况
例题
找出字符串'life is short,i use python,i love python.'
中,'life'
与'python'
之间,'python'
与'python'
之间的所有元素?
import re
s = 'life is short,i use python,i love python.'
r = re.search('life(.*)python(.*)python',s)
print(r.group(0))
print(r.group(1))
print(r.group(2))
-->
life is short,i use python,i love python #表完整的正则表达式的匹配
is short,i use #表第1个分组的匹配取值
,i love #表第2个分组的匹配取值
为更简化,将多个分组组号写到一个group里面:
import re
s = 'life is short,i use python,i love python.'
r = re.search('life(.*)python(.*)python',s)
print(r.group(0,1,2)) #在一个group函数里,指定多个组号
-->
('life is short,i use python,i love python', ' is short,i use ', ',i love ')
#把所有的结果,统一放在一个元组里
如果只想看到所有的匹配项,那就用groups():
import re
s = 'life is short,i use python,i love python.'
r = re.search('life(.*)python(.*)python',s)
print(r.groups()) #在这里,相当于就是group(1,2)
-->
(' is short,i use ', ',i love ') #只将中间的匹配项,括号里的所有结果呈现出来
(七)小结
1.正则表达式的重要性:
- 能够完成很多字符串内置函数无法完成的功能
- 目前的使用场景,多爬虫、数据处理与分析领域
2.怎么用正则表达式:
特点:正则功能强大,但细节知识点容易忘。
基于上述特点,所以:
- 为提高工作效率,建议用别人写好的,直接查阅搜索
- 为学习,稍微多花点时间,研究下内部是如何写的
正则表达式手册
https://tool.oschina.net/uploads/apidocs/jquery/regexp.html
正则表达式在线测试工具:
https://c.runoob.com/front-end/854?optionGlobl=global
Comments | NOTHING