正则表达式进阶

1,042 阅读6分钟

阅读建议:如果还没学习过正则基础的建议跳转至正则基础: 正则30分钟快速入门,文章阅读时间大概10分钟,练习题目大概需要花30分钟以上,文章准备了知识点的介绍与对应练习题,可以帮助你从理论到实践(人话:从脑子会到手也会),练习题网站:codejiaonang.com/#/course/re…

分组

在正则表达式中还提供了一种将表达式分组的机制,当使用分组时,除了获得整个匹配。还能够在匹配中选择每一个分组。

要实现分组很简单,使用()即可。

例如:

image.png

这段正则表达式将文本分成了两组,第一组为:0731,第二组为8825951

image.png

分组有一个非常重要的功能——捕获数据。所以()被称为捕获分组,用来捕获数据,当我们想要从匹配好的数据中提取关键数据的时候可以使用分组。

(\d{4})(\d{7})就分别捕获了两段数据:

  1. 0731
  2. 8825951

使用分组提取数据

接下来请你使用分组进行数据的提取。

请注意: 在这里你既需要匹配左边的数据,也需要通过分组将左侧的关键数据提取到右侧,当左侧数据匹配正确并且右侧数据提取正确就可以通关!

接下来你可以分别尝试两段正则表达式,来体验分组提取:

  1. <div>.*?</div>

  2. <div>(.*?)</div>

需要匹配的:

<div>hi</div>

需要提取的: hi

提取学号

有些学校的学号是由多个关键信息组成的,例如:2019-5013-08 2019表示入学年份,5013表示班级代码,08表示班级中的排序。

接下来请你编写正则表达式匹配不同格式的学号,并将其中的关键信息用分组提取出来,需要分成三个分组。

2019-5013-08
2019 5013 08
2019501308

答案:(\d{4})[-\s]?(\d{4})[\-\s]?(\d{2})

解释:

  • (\d{4}) 提取第一个分组
  • [-\s]? 匹配斜杠和空白 0 次或 1 次

非捕获分组

有时候,我们并不需要捕获某个分组的内容,但是又想使用分组的特性。

这个时候就可以使用非捕获组(?:表达式),从而不捕获数据,还能使用分组的功能。

例如想要匹配两个字母组成的单词或者四个字母组成的单词就可以使用非捕获分组

image.png

分组的回溯引用

正则表达式还提供了一种引用之前匹配分组的机制,有些时候,我们或许会寻找到一个子匹配,该匹配接下来会再次出现。

例如,要匹配一段 HTML 代码,比如:0123<font>提示</font>abcd,可能会编写出这样一段正则表达式:

image.png

这确实可以匹配,不过可能还有另一种情况,如果数据改成这样:<font>提示</bar>

image.png

在这里fontbar 明显不是一对正确的标签,但是我们编写的正则表达式还是将它们给匹配了,所以这个结果是错误的。

我们想让后面分组的正则也匹配font,但是现在所有形式的都会匹配。

那如果想让后面分组的正则和第一个分组的正则匹配同样的数据该如何做呢?

可以使用分组的回溯引用,使用\N可以引用编号为N的分组,因此上述例子的代码我们可以改为:

image.png

通过这个例子,可以发现 \1 表示的就是第一个分组,在这里第一个分组匹配的是 font 所以\1 就代表font

练习 - 匹配单词

接下来请你编写代码匹配符合 ab ba 这种关系的单词

练习题传送门:codejiaonang.com/#/course/re…

断言 & 环视

很多人也称先行断言和后行断言为环视,也有人叫预搜索,其实叫什么无所谓,重要的是知道如何使用它们!

先行断言和后行断言总共有四种:

  1. 正向先行断言
  2. 反向先行断言
  3. 正向后行断言
  4. 反向后行断言

正向先行断言:(?=表达式),指在某个位置向右看,表示所在位置右侧必须能匹配表达式

例如:

我喜欢你 我喜欢 我喜欢我 喜欢 喜欢你

如果要取出喜欢两个字,要求这个喜欢后面有你,这个时候就要这么写:喜欢(?=你),这就是正向先行断言

image.png

提取包含大小写字母的字符串

先行断言可以用来判断字符串是否符合特定的规则,例如提取包含至少一个大小写字母的字符串:

image.png

(?=.*?[a-z])(?=.*?)[A-Z].+ 这段正则表达式规定了匹配的字符串中必须包含至少一个大写和小写的字母

练习 - 密码强度验证

现在请你编写正则表达式进行密码强度的验证,规则如下:

  • 至少一个大写字母
  • 至少一个小写字母
  • 至少一个数字
  • 至少8个字符

左边为需要你的正则需要匹配的,右边的字符串是你的正则不需要匹配的。

练习题传送门:codejiaonang.com/#/course/re…

反向先行断言

反向先行断言(?!表达式)的作用是保证右边不能出现某字符。

例如: 我喜欢你 我喜欢 我喜欢我 喜欢 喜欢你

如果要取出喜欢两个字,要求这个喜欢后面没有你,这个时候就要这么写:喜欢(?!你),这就是反向先行断言

image.png

练习-排除邮箱

编写正则表达式匹配不是qq邮箱的数据。

练习题传送门:codejiaonang.com/#/course/re…

正向后行断言

本小节只需要你记住一句话:先行断言和后行断言只有一个区别,即先行断言从左往右看,后行断言从右往左看。

正向后行断言:(?<=表达式),指在某个位置向左看,表示所在位置左侧必须能匹配表达式

例如:如果要取出喜欢两个字,要求喜欢的前面有我后面有你,这个时候就要这么写:(?<=我)喜欢(?=你)

image.png

匹配王姓同学的名字

使用正则表达式匹配匹配王姓同学的名字。

练习题传送门:codejiaonang.com/#/course/re…

反向后行断言

反向后行断言:(?<!表达式),指在某个位置向左看,表示所在位置左侧不能匹配表达式

例如:如果要取出喜欢两个字,要求喜欢的前面没有我后面没有你,这个时候就要这么写:(?<!我)喜欢(?!你)

image.png

匹配一个美元符号中的数据

请使用正则表达式匹配一个$符号中的数据。

要匹配 $ 符号记得加上转义符 \

练习题传送门:codejiaonang.com/#/course/re…

要成为正则高手还需要做一些练习,这里有一个正则表达式的BOSS,来干掉这个BOSS吧!

传送门:codejiaonang.com/#/course/re…