学习正则表达式入门笔记

第一章:什么是正则表达式?

例:提取文字中的薪资

Python3高级开发工程师上海互教教育科技有限公司上海-浦东新区2万/每月02-18满员
测试开发工程师(C++/python)上海墨鹍数码科技有限公司上海-浦东新区2.5万/每月92-18未满员
Python3开发工程师上海德拓信息技术股份有限公司上海-徐汇区1.3万/每月02-18剩余11人
测试开发工程师(Python)赫里普(上海)信息科技有限公司上海-浦东新区1.1万/每月02-18剩余5人
Python高级开发工程师上海行动教育科技股份有限公司上海-闵行区2.8万/每月02-18剩余255人
python开发工程师上海优似腾软件开发有限公司上海-浦东新区2.5万/每月02-18满员

解题代码:

#将要分析的文本放入content中
content='''Python3高级开发工程师上海互教教育科技有限公司上海-浦东新区2万/每月02-18满员
测试开发工程师(C++/python)上海墨鹍数码科技有限公司上海-浦东新区2.5万/每月92-18未满员
Python3开发工程师上海德拓信息技术股份有限公司上海-徐汇区1.3万/每月02-18剩余11人
测试开发工程师(Python)赫里普(上海)信息科技有限公司上海-浦东新区1.1万/每月02-18剩余5人
Python高级开发工程师上海行动教育科技股份有限公司上海-闵行区2.8万/每月02-18剩余255人
python开发工程师上海优似腾软件开发有限公司上海-浦东新区2.5万/每月02-18满员
'''
#将文本内容按行放入列表
lines=content.splitlines()  #splitlines()在一段文本中按行为分隔符,把文本提取出来
for line in lines:
    # 查找'万/月'在字符中什么地方
    pos2=line.find('万/每月')
    # 都找不到
    if pos2 < 0:
        pos2=line.find('万/每月')
        if pos2 < 0:
            continue
    # 执行到治理,说明可以找到薪资关键字
    # 接下来分析 薪资 数字的起始位置
    # 方法是找到pos2前面薪资数字开始的位置
    idx = pos2-1
    # 只要是数字或者小数点,就继续往前面找
    while line[idx].isdigit() or line[idx]=='.':
        idx-=1
    # 现在idx指向薪资数字前面的那个字
    # 所有薪资开始的所有就是idx+1
    pos1=idx+1
    print(line[pos1:pos2])

用正则表达式可以写为:

import re
content='''Python3高级开发工程师上海互教教育科技有限公司上海-浦东新区2万/每月02-18满员
测试开发工程师(C++/python)上海墨鹍数码科技有限公司上海-浦东新区2.5万/每月92-18未满员
Python3开发工程师上海德拓信息技术股份有限公司上海-徐汇区1.3万/每月02-18剩余11人
测试开发工程师(Python)赫里普(上海)信息科技有限公司上海-浦东新区1.1万/每月02-18剩余5人
Python高级开发工程师上海行动教育科技股份有限公司上海-闵行区2.8万/每月02-18剩余255人
python开发工程师上海优似腾软件开发有限公司上海-浦东新区2.5万/每月02-18满员
'''
p=re.compile(r'([\d.]+)万\/每{0,1}月')
for one in p.findall(content):
	print(one)

补充知识

  1. 使用 compile 函数将正则表达式的字符串形式编译为一个 Pattern 对象,有了这个对象就可以调用正则表达式中的各种方法。
  2. re.findall函数:返回string中所有与pattern对象匹配的全部字符串,返回形式为数组。就是找到pattern对象中所有符合条件的文本。
  3. r''表示去除转义字符。

相关链接

  1. python中 r’’, b’’, u’’, f’’ 的含义

  2. 正则表达式re.compile()的使用

  3. 正则表达式在线验证

  4. 正则表达式在线验证(推荐使用)

  5. 正则表达式 - 元字符

第二章:正则表达式常见语法

普通字符

普通字符:写在正则表达式里面的普通字符都是表示:直接匹配它们。

例如:
在这里插入图片描述

如果你要找文本内所有的“python”,正则表达式就非常简单,直接输入”python“即可。汉字也是一样,直接写在正则表达式里就行了。

特殊字符

特殊字符,术语叫做metacharacters(元字符)。

它们出现在正则表达式字符串中,不是表示直接匹配它们,而是表达一些特殊的含义。

这些特殊的元字符包括下面这些:

. * + ? \ [ ] ^ $ { } | ( )

下面分别介绍各字符的含义:

点.-匹配所有的字符

.表示要匹配除了换行符之外的任何单个字符。

比如,从以下文本中,选择出所有的颜色。

苹果是绿色的
橙子是橙色的
香蕉是黄色的
乌鸦是黑色的

也就是要找到所有以结尾,并且包括前面的一个字符的词语。

就可以这样写正则表达式.色
在这里插入图片描述

其中点代表了任意的一个字符,注意是一个字符

.色合起来就是表示要找任意一个字符后面是色这个字,合起来两个字的字符串。

只要表达式正确就可以写入python代码中,如下

import re
content='''苹果是绿色的
橙子是橙色的
香蕉是黄色的
乌鸦是黑色的
'''

p=re.compile(r'.色')
for one in p.findall(content):
    print(one)

星号*-重复匹配任意次

*表示匹配前面的子表达式任意次,包括0次。

比如,你要从下面的文本中,选择每行逗号后面的字符串内容,包括逗号本身。注意,这里的逗号是中文的逗号。

苹果,是绿色的
橙子,是橙色的
香蕉,是黄色的
乌鸦,是黑色的
猴子,

就可以这样写正则表达式,.*
在这里插入图片描述

紧跟在.后面表示任意字符可以出现任意次,所以整个表达式的意思就是在逗号后面的所有字符。因为匹配包括0次,所以也包括逗号本身。

python代码如下:

import re
content='''苹果,是绿色的
橙子,是橙色的
香蕉,是黄色的
乌鸦,是黑色的
猴子,
'''

p=re.compile(r',.*')
for one in p.findall(content):
    print(one)

注意:.*在正则表达式中非常常见,表示匹配任意字符任意次数。

当然这个*前面不是非得是.,也可以是其他字符,比如:
在这里插入图片描述

加号±重复匹配多次

+表示匹配前面的子表达式一次或多次,不包含0次。

比如,还是上面的例子,你要从文本中,选择每行逗号后面的字符串内容,包括逗号本身。

但是添加一个条件,如果逗号后面没有内容,就不要选择了。

比如,下面的文本中,最后一行逗号后面没有内容,就不要选择了。

例1:

苹果,是绿色的
橙子,是橙色的
香蕉,是黄色的
乌鸦,是黑色的
猴子,

就可以这样写正则表达式,.+
在这里插入图片描述

例2:

苹果,是绿色色色色色的
橙子,是橙色的
香蕉,是黄色的
乌鸦,是绿色的
猴子,绿

正则表达式绿色*,匹配结果为
在这里插入图片描述
正则表达式绿色+,匹配结果为
在这里插入图片描述

注:*+的本质区别就是在于配前面的子表达式,*包含0次,+号不包含。

花括号{}-匹配指定次数

花括号表示前面的字符匹配指定的次数

比如,下面的文本

例1:

红彤彤、绿油油、黑乎乎、绿油油油油

表达式油{3,4}就表示匹配连续的油字至少3次,至多4次,只能匹配后面的,如下:
在这里插入图片描述
如何说不想指定范围,在花括号后面直接写上匹配次数就可以了,表达式油{4}表示连续匹配油4次,如下:
在这里插入图片描述

例2:

王亚辉,13500344799,89
徐志摩,15900785634,23
周根源,13909875678,44

如何想要匹配其中的电话号码,表达式为\d{},匹配结果如下:
在这里插入图片描述
注:\d表示匹配所有数字。

问号?

问号第一种用法-令标记变慵懒尽可能少地匹配字符

贪婪模式和非贪婪模式

我们要把下面的字符串中的所有html标签都提取出来

source='<html><head><title>Title</title>'

很容易想到使用正则表达式<.*>

写出如下代码

import re
source='<html><head><title>Title</title>'
p=re.compile(r'<.*>')
print(p.findall(source))

但运行结果,却是
在这里插入图片描述

怎么回事呢?原来在正则表达式中,'*','+'都是贪婪地,使用他们时,会尽可能得匹配内容,所有,<.*>中的星号(表示任意次数的重复),一直匹配到了字符串最后的</title>里面的e。解决这个问题就需要使用非贪婪模式,也就是在星号后面加上?,变成这样<.*?>

代码改为

import re
source='<html><head><title>Title</title>'
p=re.compile(r'<.*?>')
print(p.findall(source))

运行结果为
在这里插入图片描述

问号第二种用法-匹配0个或1个前面

有时候?可以用来代替{0,1}

反斜杠\

第一种用法:对元字符的转义

反斜杠\在正则表达式中有多种用途。

比如,我们要在下面的文本中搜索所有点前面的字符串,也包含点本身

苹果.是绿色的
橙子.是橙色的
香蕉.是黄色的

如果,我们这样写正则表达式.*.,结果为
在这里插入图片描述
这是因为因为点是一个元字符,直接出现在正则表达式中,表示匹配任意的单个字符,不能表示.这个字符本身的意思了。

怎么办呢?

如果要搜索的内容本身就包含元字符,就可以使用反斜杠进行转义。

正则表达式应该这样写:.*\.

Python代码如下

import re
content='''苹果.是绿色的
橙子.是橙色的
香蕉.是黄色的'''

p=re.compile(r'.*\.')
for one in p.findall(content):
	print(one)

结果为:
在这里插入图片描述

第二种用法:匹配某种字符类型

反斜杠后面接一些字符,表示匹配某种种类型的一个字符。

比如

\d匹配0-9之间任意一个数字字符,等价于表达式[0-9]

\D匹配任意一个不是0-9直接的数字字符,等价于表达式[^0-9]

\s匹配任意一个空白字符,包括空格、tab、换行符等,等价于表达式[^\t\n\r\f\v]

\S匹配任意一个非空白字符,等价于表达式[^\t\n\r\f\v]

\w匹配任意一个文字字符,包括大小写字母、数字、下划线,等价于表达式[a-zA-Z0-9]。缺省情况也包括Unicode文字字符,如果指定ASCLL码标记,则只包括ASCLL字母

例1:\d

表达式\d表示匹配0-9之间任意一个数字字符
在这里插入图片描述

表达式\d{11}表示匹配连续11个数字所组成的字符串,也就是电话号码了
在这里插入图片描述

例2:\D

表达式\D{2,4}可以用于匹配人名
在这里插入图片描述

例3:\w

\w在缺省情况下,也会匹配Unicode文字字符(中文字符)。

Python代码为

import re
content='''王亚辉,13500344799,89
toy,15900785634,23
周根源,13909875678,44'''

p=re.compile(r'\w',r)
for one in p.findall(content):
	print(one,end='')

在这里插入图片描述

如果只要英文的字符,Python代码为

import re
content='''王亚辉,13500344799,89
toy,15900785634,23
周根源,13909875678,44'''

p=re.compile(r'\w',re.A) #re.A表示匹配ascll码
for one in p.findall(content):
	print(one,end='')

在这里插入图片描述

  1. \w经常用于用户注册时判断用户名是否符合格式。(因为可以匹配下划线)
  2. p=re.compile(r'\w',re.A)中第二个参数re.A指定正则表达式的一些标记,叫做flag。

方括号[]-匹配几个字符之一

方括号表示要匹配某几个类型的字符。

1、

[abc]可以匹配a,b或者c里面的任意一个字符。等价于[a-c][a-c]中间的-表示一个范围从a到c。如果你想匹配所有的小写字母,可以使用[a-z]

一些元字符在括号内失去了魔法,变得和普通字符一样了。

例:

下面例子要提取正确的电话号码

王亚辉,13598344799,89
徐志摩,1b998785634,23
周根源,15999875678,44
周根源,17909875678,44
郝云摩,85980785634,23
李根源,23989875678,44

表达式为1[35]\d{9},结果如下:
在这里插入图片描述

方括号内也可以写上匹配范围,如果电话号码第二位在3到7直接都是有效的,表达式可以写为1[3-7]\d{9}
在这里插入图片描述

如果想匹配所有字母都是有效的,表达式可以写为[a-z]\d{10}

2、

[akm.]匹配a k m . 里面任意一个字符

这里面.在括号李明明不在表示匹配任意字符了,而就是表示匹配.这个字符

3、

如果在方括号中使用^,表示方括号里面的字符集合。

例:

import re
content='a1b2c3d4e5'
p=re.compile(r'[^\d]')
for one in p.findall(content):
	print(one)

[^\d]表示,选择非数字的字符

输出结果为:

a
b
c
d
e

反斜杠也可以用在方括号里面,比如[\s,.]表示匹配:任何空白字符,或者逗号,或者点。

注意:[^abc]表示匹配除了abc以外的字符,不表示除a以外的字符。

^-匹配文本的起始位置

^表示匹配文本的起始位置

起始位置和单行、多行模式

正则表达式可以设定单行模式多行模式

如果是单行模式,表示匹配整个文本的开头位置。

如果是多行模式,表示匹配文本每行的开头位置。

例:

下面的文本中,每行最前面的数字表示水果的编号,最后的数字表示价格

001-苹果价格-60
002-橙子价格-70
003-香蕉价格-80

如果我们要提取所有的水果编号,用这样的正则表达式^\d+
在这里插入图片描述

写成代码:

import re
content='''001-苹果价格-60
002-橙子价格-70
003-香蕉价格-80
'''
p=re.compile(r'^\d+')
for one in p.findall(content):
	print(one)

运行结果为:

001

这是python代码如果不加第二个参数:标记,则使用^默认为单行模式。

修改后的代码为:

import re
content='''001-苹果价格-60
002-橙子价格-70
003-香蕉价格-80
'''
p=re.compile(r'^\d+',re.M) #M或者MULTLINE
for one in p.findall(content):
	print(one)

运行结果为:

001
002
003

$-匹配文本的结束位置

如果是单行模式,表示匹配整个文本的结束位置。

如果是多行模式,表示匹配文本每行的结束位置。

例:

下面文本中,每行最前面的数字表示水果的编号,最后的数字表示价格

001-苹果价格-60
002-橙子价格-70
003-香蕉价格-80

如果我们要提取所有的水果编号,用这样的正则表达式\d+$
在这里插入图片描述

单行模式:
在这里插入图片描述

括号()-组选择

括号称之为正则表达式的组选择。是从正则表达式匹配的内容里面扣取出其中的某些部分。前面,我们有个例子,从下面的文本中,选择每行逗号前面的字符串,也包括逗号本身。

苹果,苹果是绿色的
橙子,橙子是橙色的
香蕉,香蕉是黄色的

就可以这样写正则表达式^.*,

但是,如果我们要求不要包括逗号呢?

当然不能直接这样写^.*

因为最后的逗号是特征所在,如果去掉它,就没法找逗号前面的了。

但是把逗号放在正则表达中,又会包括逗号。

解决问题的方法就是使用组选择符:括号。

我们这样写^(.*),

例1:

Python代码如下

import re
content='''苹果,苹果是绿色的
橙子,橙子是橙色的
香蕉,香蕉是黄色的
'''
p=re.compile(r'( ^.*),',re.M)
for one in p.findall(content):
	print(one)

结果如下

苹果
橙子
香蕉

例2:

如果有多组,python代码如下:

import re
content='''苹果,苹果是绿色的
橙子,橙子是橙色的
香蕉,香蕉是黄色的
'''
p=re.compile(r'(^.*)(,)',re.M)
for one in p.findall(content):
	print(one)

结果为:

('苹果', ',')
('橙子', ',')
('香蕉', ',') 

如果代码中有多个组,那么python就会将他们的结果组合成一个元祖。

例3:多组匹配的典型用法

张三,手机号码15945678991
李四,手机号码13945677781
王二,手机号码13845666981

如果想把人名和手机号码提取出来,表达式可以这样写:^(.*),.+(\d{11})

python代码:

import re
content='''张三,手机号码15945678991
李四,手机号码13945677781
王二,手机号码13845666981
'''
p=re.compile(r'^(.*),.+(\d{11})',re.M)
for one in p.findall(content):
	print(one)

结果为

('张三', '15945678991')
('李四', '13945677781')
('王二', '13845666981')

第三章:正则表达式的一些使用技巧

使用正则表达式切割字符串

字符串对象的split()方法只适用于非常简单的字符串分隔情形。当你需要更加灵活的切割字符串的时候,就不好用了。

例1:

比如,我们需要从下面字符串中提取武将的名字。

我们发现这些名字直接,有的是分号隔开,有的是空格隔开,而且分隔符号周五还有不定数量的空格

names='关于;张飞,赵云,马超,黄忠 李逵'

这时,最好使用正则表达式里面的split方法:

import re

names='关于;张飞,赵云,马超,黄忠 李逵'

namelist=re.split(r'[;,\s]\s*',names)
print(namelist)

正则表达式[;,\s]\s*指定了,分隔符为分号、逗号、空格里面的任意一种均可,并且该符号周围可以有不定数量的空格。

字符串替换

匹配模式替换

字符串对象的replace()方法只适用于简单的替换。有时,你需要风景灵活的字符串替换。

例:

比如,我们需要再下面这段文本中所有的连接中找到所有以/avxxxxx/这种以/av开头,后面接着一串数字,这种模式的字符串。然后,这些字符串全部替换为/cn3445677/

names = '''

下面是这学期要学习的课程:

<a href='https://www.bilibili.com/video/av66771949/?p=1' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是牛顿第2运动定律

<a href='https://www.bilibili.com/video/av46349552/?p=125' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是毕达哥拉斯公式

<a href='https://www.bilibili.com/video/av90571967/?p=33' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是切割磁力线
'''

例子中被替换的内容不是固定的,所以没法用字符串的replace()方法。

这时,就可以使用正则表达式里面的sub方法

import re

names = '''

下面是这学期要学习的课程:

<a href='https://www.bilibili.com/video/av66771949/?p=1' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是牛顿第2运动定律

<a href='https://www.bilibili.com/video/av46349552/?p=125' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是毕达哥拉斯公式

<a href='https://www.bilibili.com/video/av90571967/?p=33' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是切割磁力线
'''

newStr = re.sub(r'/av\d+?/', '/cn345677/' , names)
print(newStr)

sub方法也就是替换字符串,但是被替换的内容用正则表达式来表示符合特征的所有字符串。

比如,这里就是第一个参数/av\d+?/这个正则表达式,表示以/av 开头,后面是一串数字,再以 / 结尾的 这种特征的字符串 ,是需要被替换的。

第二个参数,这里是'/cn345677/' 这个字符串,表示用什么来替换。

第三个参数是源字符串。

指定替换函数

刚才的例子中,我们用来替换的是一个固定的字符串 /cn345677/

如果,我们要求,替换后的内容 的是原来的数字+6, 比如 /av66771949/ 替换为 /av66771955/

怎么办?

这种更加复杂的替换,我们可以把 sub的第2个参数 指定为一个函数 ,该函数的返回值,就是用来替换的字符串。

如下

import re

names = '''

下面是这学期要学习的课程:

<a href='https://www.bilibili.com/video/av66771949/?p=1' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是牛顿第2运动定律

<a href='https://www.bilibili.com/video/av46349552/?p=125' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是毕达哥拉斯公式

<a href='https://www.bilibili.com/video/av90571967/?p=33' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是切割磁力线
'''

# 替换函数,参数是 Match对象,当正则表达式完成匹配时sub会调用函数,同时会创建一个March类的实例对象
def subFunc(match):
    # Match对象 的 group(0) 返回的是整个匹配上的字符串, 
    src = match.group(0)
    
    # Match对象 的 group(1) 返回的是第一个group分组的内容
    number = int(match.group(1)) + 6
    dest = f'/av{number}/'

    print(f'{src} 替换为 {dest}')

    # 返回值就是最终替换的字符串
    return dest

newStr = re.sub(r'/av(\d+?)/', subFunc , names)
print(newStr)

获取组内字符串,如下

match.group(0) # 获取整个匹配字符串
match.group(1) # 获取第1个组内字符串
match.group(2) # 获取第2个组内字符串

Python 3.6 以后的版本 ,写法也可以更加简洁,直接像列表一样使用下标,如下

match[0]
match[1]
match[2]

相关链接

python group()

  1. 正则表达式中的三组括号把匹配结果分成三组

    • group() 同group(0)就是匹配正则表达式整体结果
    • group(1) 列出第一个括号匹配部分,group(2) 列出第二个括号匹配部分
    • group(3) 列出第三个括号匹配部分。
  2. 没有匹配成功的,re.search()返回None

  3. 当然郑则表达式中没有括号,group(1)肯定不对了。

教程来源

b站:https://www.bilibili.com/video/BV1q4411y7Zh
官网:www.byhy.net

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值