07 正则表达式与JSON文件之二


目录

  • 正则表达式

    • 基本概念
    • 元字符
    • 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.中,lifepython中间的所有元素提取出来?(用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

声明:Jerry's Blog|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 07 正则表达式与JSON文件之二


Follow excellence, and success will chase you.