Python实战社群

Java实战社群

长按识别下方二维码,按需求添加

扫码关注添加客服

进Python社群▲

扫码关注添加客服

进Java社群

作者丨zhenguo

来源丨Python与算法社区

今天开始Python进阶模块总结之正则专题,目录结构如下:

  • 1 学习正则的价值

  • 2 正则学习前的几个准备

    • Q1 字符 `r`是干啥的?

    • Q2 什么是一个原子操作?

    • Q3 怎么理解正则中的转义?

  • 3 掌握最常用规则

    • 情况1:最普通查找

    • 情况2:使用通用字符

    • 情况3:使用元字符

  • 4 有个棘手的场景

  • 5 学会提取子串的技能

  • 6 使用捕获的注意事项

1 学习正则的价值

正则应用广泛。不仅在Python语言中使用,其他语言也都在用,并且不同语言间的正则语法极为相似。同时主流操作系统,尤其linux系统的命令窗口中,也会经常使用到正则。还有,Python的常用包如Pandas,也经常遇到正则。

不仅使用广泛,正则功能也很强大,还有书写简便,因此这项技能值得我们仔细研究和掌握。

2 正则学习前的几个准备

Q1 字符 r是干啥的?

经常见过正则表达式前有一个字符 r,它的作用是告诉解释器后面的一串是原生字符串,按照字面意思解释即可。如:

s1 = r'\n.*'
print(s1)

它告诉编译器s串第一个字符是\,第二个字符是n.打印的结果就是它本身:

\n.*

而如果不带前缀字符r,即:

s2 = '\n.*'
print(s2)

解释器认为前两个字符\n为转义字符,一个新行的意思,打印结果为一个换行加.*,如下所示:


.*

Q2 什么是一个原子操作?

微观世界中,如果定义原子是组成事物的最基本单元,那么就可理解为原子不能再分了。同理此处,正则的原子操作是指不能再被分割的正则表达式操作。

如正则中的+指前面的一个原子操作出现至少1次。例如:66+表示第一个字符为6,第二个字符6和第三个字符+联合起来表示至少出现1次字符6,因此综合起来至少要有2个6紧邻的串才能满足此正则表达式(下面会详细讲到)。

\w+表示字母数字下划线中的任意一个字符(\w指代的)至少出现1次,那么\w就是一个原子操作。

因此,普通字符是原子,正则中的通用字符(下面会讲到)也是原子。大家记住原子这个概念。

Q3 怎么理解正则中的转义?

正则世界中,重新定义了几个新的转义字符。

一个转义字符\+一个字符,转义后会改变原字符的意义,它不再是它,而是赋予一个新的含义。

例如,w本身就是一个英文字符w,没有其他任何含义。但是,前面加一个转义字符 \ 后,含义发生重大改变,w它不再是w,而是\要与w连在一起,被解释器解释为匹配以下字符集合中的任意一个:

pat = '\w'

等于:

pat = '[0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz_]'

即匹配数字、大小写字母和下划线_字符集合中的任意一个。

你看,一个通用转义字符\w直接就指代上面这一大串,写法多么简便,同时在正则的世界里又经常被用到,故被称为:通用正则字符

类似的通用正则字符还有几个,下面也会讲到。做一件事前,把规则弄清,触类旁通,相信大家理解其他几个也没问题。

3 掌握最常用规则

为了更清晰的展示,咱们只涉及最常用的规则,一来缩短篇幅,二来降低大家学习曲线,三来一类问题掌握一个,触类旁通即可。

情况1:最普通查找

最普通查找就是需要找啥就写啥,没有使用正则的规则。如下是关于小说《灿烂千阳》中的一段话,从中找出单词friendship,可能出现多次:

s = """
# Mariam is only fifteen
# when she is sent to Kabul to marry the troubled and bitter Rasheed,
# who is thirty years her senior.
# Nearly two decades later,
# in a climate of growing unrest, tragedy strikes fifteen-year-old Laila,
# who must leave her home and join Mariam's unhappy household.
# Laila and Mariam are to find consolation in each other,
# their friendship to grow as deep as the bond between sisters,
# as strong as the ties between mother and daughter.
# With the passing of time comes Taliban rule over Afghanistan,
# the streets of Kabul loud with the sound of gunfire and bombs,
# life a desperate struggle against starvation, brutality and fear,
# the women's endurance tested beyond their worst imaginings.
# Yet love can move a person to act in unexpected ways,
# lead them to overcome the most daunting obstacles with a startling heroism.
# In the end it is love that triumphs over death and destruction.
# A Thousand Splendid Suns is an unforgettable portrait of a wounded country and
#  a deeply moving story of family and friendship.
#  It is a beautiful, heart-wrenching story of an unforgiving time,
#  an unlikely bond and an indestructible love.
"""

使用正则前,先导入re模块,再定义正则表达式,然后使用findall方法找出所有匹配

import re
pat = 'friendship'
result = re.findall(pat,s)
print(result) # 共找到两处:
# ['friendship', 'friendship']

以上就是使用正则的最普通例子。如果要找出前缀为grow的单词,比如可能为grows, growing 等,最普通查找实现起来就不方便。

然而,借助于下面介绍的元字符、通用字符和捕获组合起来,便能应对解决复杂的匹配查找问题。

情况2:使用通用字符

在正则的世界里,通用字符指帮助我们更加简便的写出匹配规则的字符。

如上面文字,下面正则匹配串能找出以d开始,[a-z]表示的任意一个小写英文字符,{7}表示小写英文字符出现7次(下面情况3会说到),也就是匹配出来的子串长度为1+7=8:

pat = 'd[a-z]{7}'
result = re.findall(pat,s)

匹配结果为:

['daughter', 'desperat', 'daunting', 'destruct', 'destruct']

同理,模式串pat = 'd[a-z]{10}'匹配的结果为:

['destruction', 'destructibl']

模式串pat = 'd[a-z]{11}'匹配的结果为:

[ 'destructible']

你看,通用字符[a-z]使用真方便,5个字符一下就表达了所有26个小写的字符,但是注意[a-z]匹配26个小写字符的任意一个.

类似功能的通用字符还包括:

[A-Z]  匹配大写英文字母
[0-9]  匹配一个0-9之间的数字

还有更加强大的通用字符:

\s  匹配空白字符,如\n \t \b等
\w  匹配任意字母、数字、下划线
\d  匹配十进制数字0-9

而\S, \W, \D 分别对应 \s, \w, \d匹配字符集的补集,例如\S 的意思是匹配 \s 以外的其他任意字符。

情况3:使用元字符

的含义大家不妨理解为用来描述它后面事物的类,如元类用来创建描述类的类,元模型描述一个模型的模型,因此推而广之,元字符用来描述字符的字符。

理解以上后,你再看正则中使用最普遍的一个元字符 +,它是用来描述前面一个原子出现次数的字符,表示前一个原子出现1次或多次都可。

例如,在寻找手机靓号时,正则表达式66+,表示前一个原子6至少出现1次,因此连上第一个6,表示电话号码中至少有两个66紧邻。因此,电话号码1861265216617566665656都满足要求,而号码18616161616不符合要求。

类似功能的元字符,还包括如下。功能相似,不再赘述:

* 前面的原子重复0次、1次、多次
? 前面的原子重复0次或者1次
+ 前面的原子重复1次或多次
{n} 前面的原子出现了 n 次
{n,} 前面的原子至少出现 n 次
{n,m} 前面的原子出现次数介于 n-m 之间

4 有个棘手的场景

了解以上规则后,我们能去完成很多匹配任务,比如一些字符串匹配任务;查找某个手机号是不是靓号;找到文字中出现某个模式的所有地方。

但是,使用正则还会经常遇到的一大场景。试想,从一个文件里提取出所有如下格式的链接,并全部导出来:

https://github.com/jackzhenguo/python-small-examples

https://gitbook.cn/gitchat/column/5e37978dec8d9033cf916b5d

截止目前,我们还不能完成这样的匹配任务。鉴于这种匹配任务确实很常见,因此你很有必要学会下面这项技能。

5 学会提取子串的技能

今天以我写过的《Python 60天》专栏中的一段文字,提取出里面的链接为例,阐述提取子串的实用性。

先贴上文字(有删减改动),将这段文字赋值给变量 urls

urls = """
基于 Python 的包更是枝繁叶茂,遍地开花,“Tiobe 编程语言排行榜”最新统计显示 Python 是增长最快的语言。![image-20200131192231967](https://images.gitbook.cn/2020-02-05-014719.png)接下来,与大家,还有远在美国做 AI 博士后研究的 Alicia,一起开始我们的 60 天 Python 探索之旅吧。所有的这些考虑,都是为了让大家在短时间内掌握 Python 技术栈,多一个生存的本领。拿到理想的 Offer 后,早日过上自己想要的生活。让我们开始吧。如下,按照是否为静态/动态语言,弱类型/强类型两个维度,总结常用的语言分类。![image-20200205155429583](https://images.gitbook.cn/2020-02-05-080211.png) ### 四大基本语法
"""

你可能很快写出如下的正则表达式:

# 元字符.表示匹配除\n字符外的任意一个字符
# 元字符*表示匹配前面一个原子0次或多次
pat = r'https:.*'

然后导入re模块,使用findall方法找出所有匹配:

import re
result = re.findall(pat,urls)
print(result)

运行结果显示如下,观察发现2个匹配,但是每个匹配链接都包括冗余字符,因此匹配错误:

['https://images.gitbook.cn
/2020-02-05-014719.png)','https://images.gitbook.cn
/2020-02-05-080211.png) ### 四大基本语法']

我们再稍微优化原正则表达式为:

# 添加 \) 表示待匹配子串以右括号结尾
pat = r'https:.*\)'

打印结果显示如下,结果确实好一点,但是依然包括右括号,结果还是错误的:

['https://images.gitbook.cn/
2020-02-05-014719.png)', 'https://images.gitbook.cn/
2020-02-05-080211.png)']

所以掌握提取子串的技能就很重要,实现提取子串也很简单,只需把想要返回的子串加上一对括号就行,如下所示:

# 把想要返回的子串外面添加一对括号pat = r'(https:.*)\)'

此时返回结果完全正确,无任何多余字符。想要返回的子串外面添加一对括号还有个专业叫法:捕获或分组。

6 使用捕获的注意事项

捕获功能非常实用,使用它需要区分一点,贪婪捕获和非贪婪捕获。前者指在满足匹配模式前提下,返回包括尽可能多的字符匹配模式;后者指满足匹配条件下,尽可能少的捕获。

我们伪造一个理想状况下的案例:

htmlContent = """<div><div><h2>这是二级标题</h2></div><div><p> 这是一个段落>/p></div></div>
"""

贪心捕获使用(.*),如下所示:

pat = r"<div>(.*)</div>"result = re.findall(pat,htmlContent)

结果为如下,尽可能长的捕获,而不是遇到第一个</div>时就终止:

['<div><h2>这是二级标题</h2></div><div><p> 这是一个段落>/p></div>']

而非贪心捕获的正则表达式为<div>(.*?)</div>",如下:

pat = r"<div>(.*?)</div>"result = re.findall(pat,htmlContent)print(result)

结果为两个元素,遇到第一个</div>时终止,然后继续捕获出第二子串:

['<div><h2>这是二级标题</h2>', '<p> 这是一个段落>/p>']

以上例子仅仅用作演示两者区别,实际的html结构含有换行符等,环境比上面要复杂的多,贪心和非贪心捕获的写法可能不会导致结果不同,但是我们依然需要理解它们的区别。

以上就是正则使用需要掌握的主要知识,整篇文章的结构总结如下:

  • 1 学习正则的价值

  • 2 正则学习前的几个准备

    • Q1 字符 `r`是干啥的?

    • Q2 什么是一个原子操作?

    • Q3 怎么理解正则中的转义?

  • 3 掌握最常用规则

    • 情况1:最普通查找

    • 情况2:使用通用字符

    • 情况3:使用元字符

  • 4 有个棘手的场景

  • 5 学会提取子串的技能

  • 6 使用捕获的注意事项

掌握以上这些正则知识后,相信就能明白主要的正则原理了。具体到有些细节时大家可参考外部的正则可视化工具和检验工具,来验证一下自己写的正则表达式就行。

程序员专栏 扫码关注填加客服 长按识别下方二维码进群近期精彩内容推荐:   955 不加班的公司名单:955.WLB 终于稳了!2020年8月程序员工资最新统计 盘点 Python 10 大常用数据结构(上篇) 理解Java反射的正确姿势在看点这里好文分享给更多人↓↓

「Python ​正则」使用专题总结相关推荐

  1. python编程a的x次方_「Python 面试」第四次更新

    阅读本文大约需要 5 分钟. 15.说一说 GIL 前面有提到由于 Python 基于 C 语言编写的解释器中设置了一个 GIL 全局变量锁,该锁使得 Python 的多线程在处理 CPU 计算密集型 ...

  2. mysql数据字典生成器_「python技术」列表推导、生成器表达式和字典推导的差异及其示例

    #开往春天新创作大赛# 前言 列表推导式构建列表的快捷方式,而生成器表达式则可以用来创建其他任何类型的序列.自python2.7以后,列表推导和生成器表达式的概念就应用到了字典上,所以就有了字典推导, ...

  3. 「分布式系统理论」系列专题

    如今互联网已经成为整个社会的基础设施,分布式系统并不是少数大公司的专属,所以分布式系统理论可能是你迟早需要掌握的知识. 如果你是程序员,相信这些文章你肯定能看懂:如果你不是程序员,相信这些能使你能更懂 ...

  4. 「分布式系统理论」系列专题整理

    以下内容出自微信公众号 跨界架构师 ,有兴趣的朋友可以参考我的博客 DotNet微信公众号简介 进行关注. [数据一致性] <分布式系统关注点(1)--数据一致性>(入门理解「一致性」) ...

  5. 「Python 编程」编码实现网络请求库中的 URL 解析器

    相信各位 Python 开发者都用过 Requests 库,有些朋友还用过 WebSockets 库.这里回顾一下它们的基本用法,例如使用 Requests 库向目标网站发出 GET 请求: impo ...

  6. 「Python入门」python环境搭建及VScode使用python运行方式

    ​ ​ 活动地址:CSDN21天学习挑战赛 文章目录 前言 一. python环境搭建 1.1 python下载安装 1.2 python安装 1.3 python环境变量配置 1.4 python版 ...

  7. 调用python_「Python 进阶」python 实现链式调用

    #!/usr/bin/env Python3# -*- coding: utf-8 -*-# @Software: PyCharm# @virtualenv:workon# @contact: 104 ...

  8. 11个好用到起飞的「Python字典」知识点!

      人生苦短,快学Python! 关于Python字典,算是Python中相当重要的数据类型了.在你学会基础知识后,字典这个概念,将会伴随着你后面的学习和工作. 因此,这里有几个相当重要的知识点,大家 ...

  9. python input输入多个变量_「Python 秘籍」1.2 解压可迭代对象赋值给多个变量

    问题 需要从某个可迭代对象中分解出 N 个元素,但是这个可迭代对象的长度可能超过 N,这会导致出现"需要解包的值过多(too many values to unpack)"的异常. ...

最新文章

  1. hashmap原理_HashMap和HashTable底层原理以及区别
  2. 针对新手的Java EE7和Maven项目–第1部分–简单的Maven项目结构–父pom
  3. 没学过编程能学python吗_我没学过编程,能否学会Python?
  4. vue命令行错误处理
  5. 编程技能和做员工的技能——哪个更重要?
  6. Linux DNS | resolv.conf 配置dns解析,重启network丢失
  7. 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
  8. AMD因虚假宣传遭集体诉讼 向消费者赔偿1210万美元
  9. c语言牛顿方法,C语言编写牛顿迭代法的跟踪
  10. 法国政府正考虑采用开源软件
  11. H264之sps解析分辨率
  12. Linux下安装Scala
  13. 代理服务器的常用端口有哪些?
  14. ligerUi框架简单的表格展示
  15. Android状态栏禁止下拉异常分析
  16. 计算机视觉(三)图像拼接
  17. 微信 及支付宝 支付接口 功能
  18. 解剖SQLSERVER 第十七篇 使用 OrcaMDF Corruptor 故意损坏数据库(译)
  19. matlab区分连续波与脉冲,【求助】连续波多谱勒和脉冲波多谱勒的区别
  20. 每日一博 - 3D架构图 cloudcraft

热门文章

  1. 杭州java程序员好找工作吗,学习路线+知识点梳理
  2. java se的命令文件_Java SE的命令文件(java、javac、javadoc等)所在目录是___
  3. 【ES6语法】Object.assign合并数组及使用案例
  4. 为什么都用西门子PLC?有什么网关兼容西门子?
  5. 日常电脑办公快捷键小技巧
  6. php经纬度之间的距离计算公式,golang与php实现计算两个经纬度之间距离的方法
  7. CPU卡设计实例及程序设计(三十)ESAM过程密钥内部认证
  8. Gartner评估:众包将掀起IT服务市场的革命
  9. CVX——begin和end
  10. Problem 3: 人造卫星的高度