分组

在正则表达式中还提供了一种将表达式分组的机制,当使用分组时,除了获得整个匹配。还能够在匹配中选择每一个分组。
要实现分组很简单,使用()即可。

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

——正则表达式进阶练习_正则表达式


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

  1. 0731
  2. 8825951
/<div>(.*?)</div>/
<div>hi</div>

提取p标签中的数据

<p>(.*?)</p>

——正则表达式进阶练习_数据_02

提取学号

些学校的学号是由多个关键信息组成的
例如:2019-5013-08 2019表示入学年份,5013表示班级代码,08表示班级中的排序。
接下来请你编写正则表达式匹配不同格式的学号,并将其中的关键信息用分组提取出来,需要分成三个分组。

(\d{4}).*(\d{4}).*(\d{2})

——正则表达式进阶练习_分隔符_03

提取年月日

(\d{4})-?\/?(\d+)-?\/?(\d+)

——正则表达式进阶练习_正则表达式_04

或者条件

使用分组的同时还可以使用 或者(or)条件。
例如要提取所有图片文件的后缀名,可以在各个后缀名之间加上一个 |符号:

(.avi|.mp4|.wmv|.rmvb)

——正则表达式进阶练习_数据_05

非捕获分组​​(?:表达式)​

有时候,我们并不需要捕获某个分组的内容,但是又想使用分组的特性。
这个时候就可以使用非捕获组​​​(?:表达式)​​​,从而不捕获数据,还能使用分组的功能。
例如想要匹配两个字母组成的单词或者四个字母组成的单词就可以使用非捕获分组:

——正则表达式进阶练习_数据_06

(?:.{2}|.{3}|.{4}|.{5})-?\:?(\d{5})
非贪婪匹配
(?:.{2,5}?)-?\:?(\d{5})

——正则表达式进阶练习_数据_07

分组使用技巧

日期可以有很多格式,例如:

20200102
2020-01-02
2020-1-2
2020.01.02
2020 01 02
2020 1 2
2020/01/02

现在我们想要使用正则表达式将其中的年月日全都提取出来。

可以发现他们唯一的区别就在于分隔符和月份与日期,这个时候可以使用​​[]​​来匹配多种情况。

——正则表达式进阶练习_开发语言_08


通过​​(\d{4})[-./\s]?(\d{1,2})[-./\s]?(\d{1,2})​​ 就可以从文本中将年月日分别提取出来了。

虽然这段正则表达式看起来内容挺多,但是还是很容易理解的,​​[-./\s]​​表示匹配三个可能出现的分隔符-./和空白,?表示匹配它们0次或者1次,其他年月日的数据使用\d{N}与分组结合就可以提取到目标数据。

(\d{4})[\-\.\s\/]?(\d{1,2})[\-\.\s\/]?(\d{1,2})

——正则表达式进阶练习_分隔符_09

提取所有电话号码

[\(]?(\d{3})[\)]?[\\.\s\-]?(\d{1,3})[\-\.\s\-]?(\d{1,4})

——正则表达式进阶练习_正则表达式_10

分组的回溯引用

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

例如,要匹配一段 HTML 代码,比如:​​0123<font>提示</font>abcd​​​,可能会编写出这样一段正则表达式:
如果想让后面分组的正则和第一个分组的正则匹配同样的数据该如何做呢?

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

——正则表达式进阶练习_分隔符_11

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

(\w)(\w).*(\2)(\1)

——正则表达式进阶练习_正则表达式_12

回溯引用的实践

请编写正则表达式匹配下列有重复的数据:

(\w{2,4}?)\1

——正则表达式进阶练习_开发语言_13

正向先行断言/后置肯定断言

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

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

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

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

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

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

——正则表达式进阶练习_开发语言_14

(?=.*?[a-z])(?=.*?[A-Z]).+

——正则表达式进阶练习_分隔符_15

密码强度验证

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

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

(?=.*?[a-z])(?=.*?[A-Z]).{8}

——正则表达式进阶练习_正则表达式_16

反向先行断言/后置否定断言

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

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

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

——正则表达式进阶练习_正则表达式_17

排除邮箱

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

\w+@(?!qq)

——正则表达式进阶练习_数据_18

匹配标签

编写正则表达式匹配除​​<p>或</p>​​之外的所有标签。

<(?!p).+></(?!p).+>

——正则表达式进阶练习_开发语言_19

正向后行断言/前置肯定断言

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

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

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

——正则表达式进阶练习_分隔符_20

匹配王姓同学的名字

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

(?<=).+

——正则表达式进阶练习_正则表达式_21

反向后行断言/前置否定断言

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

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

——正则表达式进阶练习_分隔符_22

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

(?<!\$)\$([^\$]+)\$(?!\$)

——正则表达式进阶练习_数据_23

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

^\$\$(?!\$).*\$\$

——正则表达式进阶练习_分隔符_24

实践:提取所有人的生日

(?<=[.\-])(\d{1,2})(?=[.\-])[.\-](\d{1,2})

——正则表达式进阶练习_开发语言_25

实践:匹配所有的小数

^\d+\.(\d+)(?!.)

——正则表达式进阶练习_开发语言_26