分组
在正则表达式中还提供了一种将表达式分组的机制,当使用分组时,除了获得整个匹配。还能够在匹配中选择每一个分组。
要实现分组很简单,使用 () 即可。
例如:
这段正则表达式将文本分成了两组,第一组为:0731,第二组为 8825951。
分组有一个非常重要的功能——捕获数据。所以 () 被称为捕获分组,用来捕获数据,当我们想要从匹配好的数据中提取关键数据的时候可以使用分组。
(\d{4}) 和 (\d{7})就分别捕获了两段数据:
- 0731
- 8825951
或者条件
使用分组的同时还可以使用 或者(or)条件。
例如要提取所有图片文件的后缀名,可以在各个后缀名之间加上一个 | 符号:
非捕获分组
有时候,我们并不需要捕获某个分组的内容,但是又想使用分组的特性。
这个时候就可以使用非捕获组(?: 表达式),从而不捕获数据,还能使用分组的功能。
例如想要匹配两个字母组成的单词或者四个字母组成的单词就可以使用非捕获分组:
分组使用技巧
日期可以有很多格式,例如:
20200102
2020-01-02
2020-1-2
2020.01.02
2020 01 02
2020 1 2
2020/01/02
Copy
现在我们想要使用正则表达式将其中的年月日全都提取出来。
可以发现他们唯一的区别就在于分隔符和月份与日期,这个时候可以使用 [] 来匹配多种情况。
例如:
通过(\d{4})[-./\s]?(\d{1,2})[-./\s]?(\d{1,2}) 就可以从文本中将年月日分别提取出来了。
虽然这段正则表达式看起来内容挺多,但是还是很容易理解的,[-./\s]表示匹配三个可能出现的分隔符 -./ 和空白,? 表示匹配它们 0 次或者 1 次,其他年月日的数据使用 \d{N}与分组结合就可以提取到目标数据。
分组的回溯引用
正则表达式还提供了一种引用之前匹配分组的机制,有些时候,我们或许会寻找到一个子匹配,该匹配接下来会再次出现。
例如,要匹配一段 HTML 代码,比如:0123<font> 提示 </font>abcd,可能会编写出这样一段正则表达式:
这确实可以匹配,不过可能还有另一种情况,如果数据改成这样:<font> 提示 </bar>
在这里 font 和 bar 明显不是一对正确的标签,但是我们编写的正则表达式还是将它们给匹配了,所以这个结果是错误的。
我们想让后面分组的正则也匹配 font,但是现在所有形式的都会匹配。
那如果想让后面分组的正则和第一个分组的正则匹配同样的数据该如何做呢?
可以使用分组的回溯引用,使用 \N 可以引用编号为 N 的分组,因此上述例子的代码我们可以改为:
通过这个例子,可以发现 \1 表示的就是第一个分组,在这里第一个分组匹配的是 font 所以 \1 就代表 font。
正向先行断言
很多人也称先行断言和后行断言为环视,也有人叫预搜索,其实叫什么无所谓,重要的是知道如何使用它们!
先行断言和后行断言总共有四种:
- 正向先行断言
- 反向先行断言
- 正向后行断言
- 反向后行断言
正向先行断言:(?= 表达式),指在某个位置向右看,表示所在位置右侧必须能匹配表达式
例如:
我喜欢你 我喜欢 我喜欢我 喜欢 喜欢你
如果要取出喜欢两个字,要求这个喜欢后面有你,这个时候就要这么写:喜欢(?= 你),这就是正向先行断言。
提取包含大小写字母的字符串
先行断言可以用来判断字符串是否符合特定的规则,例如提取包含至少一个大小写字母的字符串:
(?=.*?[a-z])(?=.*?[A-Z]).+ 这段正则表达式规定了匹配的字符串中必须包含至少一个大写和小写的字母。
反向先行断言
反向先行断言 (?! 表达式) 的作用是保证右边不能出现某字符。
例如: 我喜欢你 我喜欢 我喜欢我 喜欢 喜欢你
如果要取出喜欢两个字,要求这个喜欢后面没有你,这个时候就要这么写:喜欢(?! 你),这就是反向先行断言。
正向后行断言
只需要你记住一句话:先行断言和后行断言只有一个区别,即先行断言从左往右看,后行断言从右往左看。
正向后行断言:(?<= 表达式),指在某个位置向左看,表示所在位置左侧必须能匹配表达式
例如:如果要取出喜欢两个字,要求喜欢的前面有我,后面有你,这个时候就要这么写:(?<= 我)喜欢(?= 你)。
反向后行断言
反向后行断言:(?<! 表达式),指在某个位置向左看,表示所在位置左侧不能匹配表达式
例如:如果要取出喜欢两个字,要求喜欢的前面没有我,后面没有你,这个时候就要这么写:(?<! 我)喜欢(?! 你)。
匹配一个美元符号中的数据
请使用正则表达式匹配一个 $ 符号中的数据。
要匹配 $ 符号记得加上转义符 \ 哦