专栏首页志学Python系统地学习正则表达式(二):进阶篇

系统地学习正则表达式(二):进阶篇

理解子表达式

通过()括起来的就是子表达式。

下面是一个例子:用来匹配IP 地址的正则表达式。IP 地址是由" . "分隔的四组数字,如12.159.46.200。因为每个部分的数字都可以为一个、两个或者三个数字字符,这个匹配模式可以表示为\d{1,3}

正则表达式:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
待匹配文本:12.159.46.200
匹配后结果:12.159.46.200

分析:每个\d{1,3}的实例都匹配了 IP 地址的一个数字。四个数字则是被\.表示的" . "分隔开的。\d{1,3}\.模式重复了三遍,因此可以使用重复操作来处理。下面是相同例子的另外一个版本:

正则表达式:(\d{1,3}\.){3}\d{1,3}
待匹配文本:12.159.46.200
匹配后结果:12.159.46.200

分析:此模式可以和前面的效果是一样的。表达式\d{1,3}\.使用()括起来从而组成子表达式。(\d{1,3}\.){3}重复了子表达式三次(也就是 IP 地址的前三个数字),最后的\d{1,3}匹配最后的数字。

使用子表达式来分组是很重要的,尽管这个例子中根本不包括重复。来看一个例子:

正则表达式:19|20\d{2}
待匹配文本:1967-08-17
匹配后结果:1967-08-17

分析:19|20\d{2}用来定位一个前两个数字只能为 19或者20的四位数的年份。但是很显然这个正则并没有实现预想的效果。|操作符从左到右读取,将19|20\d{2}分析为要么19 ,要么20\d{2},也就是匹配数字 19 或者20开头的四个数字字符

解决方法是将19|20作为一个子表达式,(19|20)\d{2}就能够匹配所有19 和 20 开头的四个数字了。

嵌套子表达式

子表达式可以嵌套。实际上,子表达式可以一层一层嵌套在子表达式内。为了演示嵌套子表达式的用法,我们再来看看查找 IP 地址的例子。

其实上面例子中(\d{1,3}\.){3}\d{1,3}匹配IP 地址是有问题的,因为非法的 IP 地址也将被匹配。IP 地址中的每个数字都是小于 255 的。而上面的模式可以匹配 300甚至是999 ,而这些实际上都是非法的 IP 地址。

下面定义了所有合法 IP 地址所需要满足的一种条件:

所有的一位数和两位数
三位数的第一位为 1
如果三位数的第一位为 2 ,且第二位从 0 到 4
如果三位数的前二位为 25 ,且第三位从 0 到 5

当定义了需要匹配的情况后,就比较容易实现可以工作的模式。下面是个例子: (((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))

分析:这个模式可以工作的原因是一系列的嵌套子表达式。首先从(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.)子表达式开始。包含了四个嵌套子表达式。(\d{1,2})可以匹配一位数和两位数(0到99)。(1\d{2})匹配了任何第一位为 1 的三位数(100到199) 。(2[0-4]\d)匹配数字从 200 到 249 。(25[0-5])匹配数字从 250 到 255 。每个子表达式都是通过“ | ”包括在另一个子表达式中。在数字范围之后是\.表示的" . ",然后这个系列括起来作为子表达式并重复三遍(使用{3})。最后,((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))被用来匹配最后一个 IP 地址的数字(没有了\.后缀)。由于将四个数字都是限制在了 0 到 255 之间,所以此模式可以匹配所有的合法 IP 地址。

理解后向引用

HTML 开发者经常使用标题标签(<H1>到<H6>,包括相应的结束标签</H1>到</H6>)。假设你需要定位所有的标题标签:

正则表达式:<[hH][1-6]>.*?</[hH][1-6]>
待匹配文本:<H1>title 1</H1> — <H6>title 6</H6>
匹配后结果:<H1>title 1</H1> — <H6>title 6</H6>

分析:<[hH][1-6]>可以匹配所有的开始标签,而</[hH][1-6]>可以匹配所有的结束标签。

注意:我们这里使用了.*?而不是.*。正如在上一篇文章解释的一样,*的量词是贪婪的,所以模式<[hH][1-6]>.*</[hH][1-6]>将匹配从<H1> 直到 </H6> 。所以可以使用非贪婪量词.*?来解决这个问题。

接着看这个例子:

正则表达式:<[hH][1-6]>.*?</[hH][1-6]>
待匹配文本:<H1>title</H6>
匹配后结果:<H1>title</H6>

分析:采用 <H1> 开始而采用 </H6> 的标题标签是非法的,但是现在的模式可以匹配。问题在于匹配的第二个部分(匹配结束的标签)没有办法知道匹配第一部分(匹配开始的标签)是什么。这时候就需要后向引用了。

使用后向引用匹配

后向应用就是引用前面的子表达式。你可以将后向应用理解成变量。例如\1匹配模式中第一个子表达式。同理,\2将匹配第二个子表达式,\3将匹配第三个。我们结合例子来理解。一个子表达式可以通过后向引用根据需要引用多次。

在上个例子中,<[hH][1-6]>.*?</[hH][1-6]>会匹配非法的标题。我们可以使用后向引用来解决:

正则表达式:<[hH]([1-6])>.*?</[hH]\1>
待匹配文本:<H1>title</H1>—<H1>title</H6>
匹配后结果:<H1>title</H1>—<H1>title</H6>

分析:就像以前一样,<[hH]([1-6])>将匹配任何的标题标签。但是和以前不一样的是,这里的[1-6]使用了小括号括起来成为了子表达式。这样,匹配结束标签的模式可以通过</[hH]\1>中的\1来引用此子表达式。(1-6)是一个可以匹配数字 1 到 6 的子表达式,\1因此可以匹配相同的数字。在这种情况下,"<H1>title</H6>"将不能匹配。

注意:后向引用只能够引用子表达式(需要使用小括号括起来),后向引用语法在不同的正则表达式实现中可能是不一样的。引用的匹配一般是从 1 开始。在大多数的正则表达式实现中,0 可以用来引用整个表达式。

执行替换操作

到现在为止我们所看到的正则表达式都是进行搜索,在一段文本中定位单词。正则表达式还可以用来执行替换操作。举个例子,将CA 替换成California和将MI替换成Michigan 并不是正则表达式需要完成的工作。尽管使用正则表达式也是合法的,但是没有必要这么做。事实上,在这里如果使用简单的字符串操作函数的话过程将会变得更加容易。

让我们来看一个例子,将313-555-1234格式的电话号码重新格式化为(313) 555-1234格式:

查找表达式:(\d{3})(-)(\d{3})(-)(\d{4})
替换表达式:($1) $3-$5

文本
313-555-1234

248-555-9999

结果

(313) 555-1234
(248) 555-9999

分析:(\d{3})(-)(\d{3})(-)(\d{4})匹配了一个电话号码,并分成了五个子表达式。(\d{3})匹配刚开始的三个数字并作为第一个子表达式,(-)匹配" - "并作为第二个子表达式,依此类推。这五个部分可以根据需要单独引用,($1) $3-$5只是使用了其中的三个子表达式。因此“313-555-1234”改变为了“(313) 555-1234”。

本文分享自微信公众号 - 志学Python(gh_755651538c61)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-10-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 干货|深度学习中的正则化技术概述(附Python+keras实现代码)

    数据科学研究者们最常遇见的问题之一就是怎样避免过拟合。你也许在训练模型的时候也遇到过同样的问题--在训练数据上表现非同一般的好,却在测试集上表现很一般。或者是你...

    小草AI
  • Flask支持正则路径匹配

    •default([^/].*?)•string•int•float•path•uuid

    上帝De助手
  • 一文读懂线性回归、岭回归和Lasso回归

    本文介绍线性回归模型,从梯度下降和最小二乘的角度来求解线性回归问题,以概率的方式解释了线性回归为什么采用平方损失,然后介绍了线性回归中常用的两种范数来解决过拟合...

    AI科技大本营
  • Python3中正则表达式使用方法

    崔庆才,Python技术控,爬虫博文访问量已过百万。喜欢钻研,热爱生活,乐于分享。

    生信宝典
  • 爬虫篇 | Python爬虫学前普及

    最近整理一个爬虫系列方面的文章,不管大家的基础如何,我从头开始整一个爬虫系列方面的文章,让大家循序渐进的学习爬虫,小白也没有学习障碍.

    叫我龙总
  • 【JS】369- 20个常用的JavaScript字符串方法

    concat() 方法用于连接两个或多个字符串,此方法不改变现有的字符串,返回拼接后的新的字符串。

    pingan8787
  • 图文解读助你理解和使用正则表达式

    对于大多数没有接受过正式 CS 教育的人来说,正则表达式似乎只有最核心的 Unix 程序员才敢碰。

    Datawhale
  • 爬虫篇 | Python使用正则来爬取豆瓣图书数据

    最近整理一个爬虫系列方面的文章,不管大家的基础如何,我从头开始整一个爬虫系列方面的文章,让大家循序渐进的学习爬虫,小白也没有学习障碍.

    叫我龙总
  • 推荐收藏 | 10道XGBoost面试题送给你

    XGBoost的威名想必大家都有所耳闻,它不仅是数据科学竞赛神器,在工业界中也被广泛地使用。本文给大家分享珍藏了多年的XGBoost高频面试题,希望能够加深大家...

    Sam Gor
  • 基础测试: 该正则可以匹配下列哪个字符串? /^sjm/

    舒克

扫码关注云+社区

领取腾讯云代金券