捕获分组 () 匹配到的真实文本,可以在同一个正则里面再次拿出来复用,就是后向引用
编号规则:从左往右,按左括号出现顺序编号,\1 代表第1个分组捕获到的内容,\2 第2个分组,以此类推。
1. 示例
匹配连续重复单词
正则:
\b([a-z]+)\b\s+\1\b
Code language: CSS (css)
拆解:
\b:单词边界([a-z]+):分组1,捕获一串小写单词(比如go、sit)\b:单词边界\s+:一个或多个空白(空格)\1:反向引用,代表分组1捕获到的那一段文字 不是重复表达式[a-z]+!而是匹配到的真实字符串。 如果分组捕获了go,\1就代表文本go;捕获sit,\1就是sit\b:单词边界
可以匹配:go go、sit sit
不能匹配 go sit,因为 \1 必须和前面分组抓到的文字一模一样。
区分重点:
([a-z]+) \1:内容必须相同,go go✔,go soX([a-z]+) ([a-z]+):两个独立单词,内容可以不一样,go so✔
2. 命名分组
给分组起名字,不再只用数字编号
数字分组
\1 \2简单,但分组一多,容易搞混序号。可以给分组命名。
语法(两种写法)
(?<Word>[a-z]+) # 尖括号写法 .NET、PCRE、JS等大部分引擎支持
(?'Word'[a-z]+) # 单引号写法,.NET 常用
Code language: PHP (php)
反向引用命名分组用:\k<Word> 改写上面重复单词例子:
\b(?<Word>[a-z]+)\b\s+\k<Word>\b
Code language: HTML, XML (xml)
含义和 \b([a-z]+)\b\s+\1\b 完全一样,只是分组有名字 Word。
3. 常见实用场景
1:匹配成对 HTML 标签
<([a-z]+)>.*?</\1>
Code language: HTML, XML (xml)
([a-z]+)捕获标签名div/p\1引用捕获到的标签名,保证开始标签和结束标签名字一致 匹配:<p>hello</p>√ 不匹配:<p>hello</div>x
2:匹配连续重复字符,比如 aaaa、bbbb
(\w)\1\1\1
(\w) 捕获单个字符,后面连续引用3次,匹配4个相同字符。
注意
- 后向引用引用的是匹配到的文本,不是表达式本身!
([0-9])\1匹配55,不是56。 - 分组编号只看左括号顺序,嵌套分组也是从左括号开始数。
((a)(b))分组1:((a)(b)),分组2:(a),分组3:(b) - 非捕获分组
(?:)不会产生编号,不能反向引用!(?:[a-z]+)\s+\1报错,没有分组1。 - 后向引用只能在正则内部使用,在替换/代码里,语法会变成
$1(比如 JS、C#)。
思考题
正则:(\d)\1,下面哪个字符串能匹配成功?
122223
答案 2. `22` 分组捕获 `2`,`\1` 引用 `2`,所以 `22` 匹配。
Previous: 反义匹配(负类)
Next: 零宽断言 & 负向零宽断言