后向引用(反向引用)

捕获分组 () 匹配到的真实文本,可以在同一个正则里面再次拿出来复用,就是后向引用
编号规则:从左往右,按左括号出现顺序编号,\1 代表第1个分组捕获到的内容,\2 第2个分组,以此类推。

1. 示例

匹配连续重复单词

正则:

\b([a-z]+)\b\s+\1\b
Code language: CSS (css)

拆解:

  1. \b:单词边界
  2. ([a-z]+)分组1,捕获一串小写单词(比如 gosit
  3. \b:单词边界
  4. \s+:一个或多个空白(空格)
  5. \1反向引用,代表分组1捕获到的那一段文字 不是重复表达式 [a-z]+!而是匹配到的真实字符串。 如果分组捕获了 go\1 就代表文本 go;捕获 sit\1 就是 sit
  6. \b:单词边界

可以匹配:go gosit sit

不能匹配 go sit,因为 \1 必须和前面分组抓到的文字一模一样。

区分重点:

  • ([a-z]+) \1内容必须相同go go ✔,go so X
  • ([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:匹配连续重复字符,比如 aaaabbbb

(\w)\1\1\1

(\w) 捕获单个字符,后面连续引用3次,匹配4个相同字符。

注意

  1. 后向引用引用的是匹配到的文本,不是表达式本身! ([0-9])\1 匹配 55,不是 56
  2. 分组编号只看左括号顺序,嵌套分组也是从左括号开始数。((a)(b)) 分组1:((a)(b)),分组2:(a),分组3:(b)
  3. 非捕获分组 (?:) 不会产生编号,不能反向引用! (?:[a-z]+)\s+\1 报错,没有分组1。
  4. 后向引用只能在正则内部使用,在替换/代码里,语法会变成 $1(比如 JS、C#)。

思考题

正则:(\d)\1,下面哪个字符串能匹配成功?

  1. 12
  2. 22
  3. 23

答案 2. `22` 分组捕获 `2`,`\1` 引用 `2`,所以 `22` 匹配。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注