正则表达式

一个文本文件里面存储了 一些市场职位信息,格式如下所示:

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

import re
for one in  re.findall(r'([\d.]+)万/每{0,1}月', content):
    print(one)
re.findall(r'([\d.]+)万/每{0,1}月', content)

1.点-匹配所有字符:

. 表示要匹配除了 换行符 之外的任何 单个 字符。(必须有一个字符,不能是空字符)

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

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

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

import re 是导入正则表达式的包,re是正则表达式的简称。

高亮行 re.compile 函数返回的是 正则表达式对象,它对应的匹配规则在参数中进行定义

后面 可以 调用这个对象的 findall 方法来进行正则表达式搜索操作。

re.compile :compile其实是正则表达式中的一个叫pattern类的对象,有了这个对象我们就可以调用pattern对象的各种方法进行处理,比如findall();。

如果你只是 一次性 使用 这个匹配规则,可以不用先 re.compile 产生正则表达式对象,

可以直接使用 re.findall 函数,如下:

import re
for one in  re.findall(r'.色', content):
    print(one)

r 的作用:正则表达式中(r'.色',content)中的 r 的作用是防止正则表达式出现乌龙事件,告诉计算机正式正则表达式的语法结构。(最好加上,不加其实也可以)。

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

2.星号--重复匹配任意次:

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

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

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

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

就可以这样写正则表达式: 

,.*

* 紧跟在 . 后面,表示任意字符可以出现任意次,所以整个正则式的意思就是在逗号后面的所有字符,包括逗号。

3.加号--重复匹配多次:

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

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

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

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

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

验证如图:

最后一行,猴子逗号后面没有其它字符了,+表示至少匹配1次, 所以最后一行没有子串选中。


4.问号--匹配0-1次:

?表示匹配前面的子表达式0次或1次。

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

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

我们使用正则表达式:

,.?

验证一下:

最后一行,猴子逗号后面没有其它字符了,但是?表示匹配1次或0次, 所以最后一行也选中了一个逗号字符。

5.花括号--匹配指定次数:

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

红彤彤,绿油油,黑乎乎,绿油油油油

表达式 油{3} 就表示匹配 连续的 油 字 3次

表达式 油{3,4} 就表示匹配 连续的 油 字 至少3次,至多 4 次

就只能匹配 后面的,如下所示:

6.贪婪模式和非贪婪模式:

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

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

我们使用正则表达式:

<.*>

验证如图所示:

结果并不是我们想要的,怎么回事? 原来 在正则表达式中, '*', '+', '?' 都是贪婪地,使用他们时,会尽可能多的匹配内容,所以, <.*> 中的 星号(表示任意次数的重复),它们将最左边的<和最右边的>进行了匹配,因此括号内的内容都取了出来。解决这个问题,就需要使用非贪婪模式,也就是在星号后面加上 ? ,?表示匹配前面的子表达式0次或者1次。

因此正则表达式改写为:

<.*?>

验证如图:

7.对元字符的转义:

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

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

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

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

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

这里我们就应用使用这样的表达式: 

.*\.

示例:

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

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

运行结果如下:

苹果.
橙子.
香蕉.

8.匹配某种字符类型:

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

比如:

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

2.\D 匹配任意一个非0-9数字的字符,等价于表达式 [^0-9]。

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

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

5.\w 匹配任意一个文字字符,包括大小写字母、数字、下划线,等价于表达式 [a-zA-Z0-9_]。

缺省情况也包括 Unicode文字字符,如果指定 ASCII 码标记,则只包括ASCII字母。

6.\W 匹配任意一个非文字字符,等价于表达式 [^a-zA-Z0-9_]。

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

9.方括号--匹配几个字符之一:

方括号表示要匹配 指定的几个字符之一 。

比如:[abc] 可以匹配 a, b, 或者 c 里面的任意一个字符,等价于 [a-c] 。

[a-c] 中间的 - 表示一个范围从a 到 c。

[a-z] : 表示匹配所有的小写字母。

一些元字符在方括号内失去了魔法,变得和普通字符一样。比如:[akm.] 匹配 a k m . 里面任意一个字符,这里 . 在括号里面不在表示匹配任意字符了,而就是表示匹配 . 这个字符。

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

比如:

content = 'a1b2c3d4e5'

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

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

运行结果为:

a
b
c
d
e

10.起始,结尾位置和单行,多行模式:

^ 表示匹配文本的 开头 位置。

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

正则表达式可以设定 单行模式 和 多行模式 : 如果是 单行模式 ,表示匹配 整个文本 的开头位置。

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

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

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

如果我们要提取所有的水果编号,用这样的正则表达式^\d+。

上面的正则表达式,使用在Python程序里面,如下所示:

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

import re
p = re.compile(r'^\d+', re.M)
for one in  p.findall(content):
    print(one)

注意,compile 的第二个参数 re.M ,指明了使用多行模式,表示匹配文本每行的开头位置。

运行结果如下:

001
002
003

如果,去掉 compile 的第二个参数 re.M, 运行结果如下:

001

运行结果就只有第一行了。因为单行模式下,^ 只会匹配整个文本的开头位置。

11. $表示匹配文本的结尾位置:

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

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

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

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

如果我们要提取所有的水果价格,用这样的正则表达式 \d+$。

对应代码:

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

import re
p = re.compile(r'\d+$', re.MULTILINE)
for one in  p.findall(content):
    print(one)

注意,compile 的第二个参数 re.MULTILINE ,指明了使用多行模式,表示匹配文本每行开头位置。

运行结果如下:

60
70
80

如果,去掉 compile 的第二个参数 re.MULTILINE, 运行结果如下:

80

就只有最后一行了。因为单行模式下,表示匹配文本整个文本的结尾位置,故$ 只会匹配整个文本的结束位置。

12.竖线--匹配其中之一:

竖线表示匹配其中之一。

比如:

特别要注意的是, 竖线在正则表达式的优先级是最低的, 这就意味着,竖线隔开的部分是一个整体。比如 绿色|橙 表示 要匹配是 绿色 或者  ,而不是 绿色 或者 绿橙。

13.括号--分组:

括号称之为正则表达式的组选择。就是把正则表达式匹配的内容里面其中的某些部分标记为某个组。我们可以在正则表达式中标记多个组。

为什么要有组的概念呢?因为有时,我们需要提取已经匹配的内容里面的某个部分 。

前面,我们有个例子,从下面的文本中,选择每行逗号前面的字符串,也包括逗号本身 。

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

就可以这样写正则表达式 ^.*, 。但是,如果我们要求 不要包括逗号 呢?当然不能直接这写 ^.*因为最后的逗号是特征所在, 如果去掉它,就没法找 逗号前面的了。但是把逗号放在正则表达式中,又会包含逗号。解决问题的方法就是使用 组选择符 : 括号。

我们这样写 正则表达式:

^(.*),

结果如下:

分组:

大家可以发现,我们把要从整个表达式中提取的部分放在括号中,这样水果的名字就被单独的放在 组 group 中了。

对应的Python代码如下:

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

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

分组还可以多次使用。

比如,我们要从下面的文本中,提取出每个人的 名字 和对应的 手机号。

张三,手机号码15945678901
李四,手机号码13945677701
王二,手机号码13845666901

我们可以使用正则表达式:

分组:

当有多个分组的时候,我们可以使用 (?P<分组名>...) 这样的格式,给每个分组命名。

这样做的好处是,更方便后续的代码提取每个分组里面的内容。

比如:

content = '''张三,手机号码15945678901
李四,手机号码13945677701
王二,手机号码13845666901'''

import re
p = re.compile(r'^(?P<name>.+),.+(?P<phone>\d{11})', re.MULTILINE)
for match in  p.finditer(content):
    print(match.group('name'))
    print(match.group('phone'))

运行结果:

让点匹配换行:

前面说过,  是 不匹配换行符 的,可是有时候,特征字符串就是跨行的,比如要找出下面文字中所有的职位名称

<div class="el">
        <p class="t1">           
            <span>
                <a>Python开发工程师</a>
            </span>
        </p>
        <span class="t2">南京</span>
        <span class="t3">1.5-2万/月</span>
</div>
<div class="el">
        <p class="t1">
            <span>
                <a>java开发工程师</a>
            </span>
        </p>
        <span class="t2">苏州</span>
        <span class="t3">1.5-2/月</span>
</div>

如果你直接使用表达式:

class=\"t1">.*?<a>(.*?)</a>

会发现匹配不上,因为t1和<a>之间有两个空行。这是你需要点也匹配换行符,可以使用DOTALL参数。

代码如下:

content = '''
<div class="el">
        <p class="t1">           
            <span>
                <a>Python开发工程师</a>
            </span>
        </p>
        <span class="t2">南京</span>
        <span class="t3">1.5-2万/月</span>
</div>
<div class="el">
        <p class="t1">
            <span>
                <a>java开发工程师</a>
            </span>
        </p>
        <span class="t2">苏州</span>
        <span class="t3">1.5-2/月</span>
</div>
'''

import re
p = re.compile(r'class=\"t1\">.*?<a>(.*?)</a>', re.DOTALL)
for one in  p.findall(content):
    print(one)

从下面的文本里面抓取 所有职位的薪资。

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

我们使用正则表达式是:

([\d.]+)万/每{0,1}月

[\d.]+ 表示 匹配 数字或者点的多次出现 这就可以匹配像: 3 33 33.33 这样的 数字

万/每{0,1}月 是后面紧接着的,如果没有这个,就会匹配到别的数字, 比如 Python3 里面的3。

其中 每{0,1}月 这部分表示匹配 每月 每 这个字可以出现 0次或者1次。也可以使用

每?月

因为问号表示前面的字符匹配0次或者1次。

14.切割字符串:

字符串对象的split方法只适用于简单的字符串分割。 有时你需要更加灵活的字符串切割。比如,我们需要从下面字符串中提取武将的名字。

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

我们发现这些名字之间,有的是分号隔开,有的是逗号隔开,有的是空格隔开, 而且分割符号周围还有不定数量的空格。

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

import re

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有梦想的小晨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值