跳到主要内容

8.1 回溯引用有什么用?

为了理解回溯引用的概念,我们最好是看一个例子,前端程序员经常使用标题标签(<h1><h6>,以及配对的结束标签)来定义和排版网页里面的标题文字。

现在,我们不妨假设你需要把某个页面里的所有标题全部查找出来,而不管它的级别是多少。看下面的例子:

<h1>.*</h1>
在工具中查看
<body>
  <h1>玩转正则表达式教程</h1>
  欢迎来到正则表达式教程
  <h2>第一章 正则表达式入门</h2>
  正则表达式入门
  <h3>1.1 正则表达式的用途</h3>
  正则表达式的用途
  <h3>1.2 如何使用正则表达式</h3>
  如何使用正则表达式
  <h2>第二章 匹配单个字符</h2>
  匹配单个字符
  <h3>2.1 匹配普通文本</h3>
  匹配普通文本
  <h3>2.2 匹配任意字符</h3>
  匹配任意字符
  <h2>第三章 匹配一组字符</h2>
  匹配一组字符
  <h3>3.1 匹配多个字符中的某一个</h3>
  匹配多个字符中的某一个
  <h3>3.2 利用字符集合区间</h3>
  利用字符集合区间
</body>

模式 <h1>.*</h1> 只能匹配一级标题,但我们说的是匹配任意级别的标题,这应该怎么办呢?最好的办法是用一个字符集合来代替 1,看下面的例子:

<h[1-6]>.*?</h[1-6]>
在工具中查看
<body>
  <h1>玩转正则表达式教程</h1>
  欢迎来到正则表达式教程
  <h2>第一章 正则表达式入门</h2>
  正则表达式入门
  <h3>1.1 正则表达式的用途</h3>
  正则表达式的用途
  <h3>1.2 如何使用正则表达式</h3>
  如何使用正则表达式
  <h2>第二章 匹配单个字符</h2>
  匹配单个字符
  <h3>2.1 匹配普通文本</h3>
  匹配普通文本
  <h3>2.2 匹配任意字符</h3>
  匹配任意字符
  <h2>第三章 匹配一组字符</h2>
  匹配一组字符
  <h3>3.1 匹配多个字符中的某一个</h3>
  匹配多个字符中的某一个
  <h3>3.2 利用字符集合区间</h3>
  利用字符集合区间
</body>

这个模式看起来不错,匹配任何一级标题的开始标签和结束标签。

注意

这里使用的是 .*? (懒惰型)而不是 .* (贪婪型)。我们在 第五章 里讲过, * 和其他几个元字符是“贪婪型”元字符,所以模式 <h[1-6]>.*?</h[1-6]> 有可能会从第 2 行的<h1>一直匹配到最后面的 </h2>,这可不是我们想要的结果;使用“懒惰型”元字符. *? 解决了这个问题。

之所以说“有可能”而不是“肯定”,是因为在这个特定的例子里即便是使用了“贪婪型”元字符也不一定会有问题。一般来说,元字符 . 不匹配换行符,而上例中的每个标题都各自占据一行。但在这里使用懒惰型元字符没有任何坏处——事前小心总比事后后悔好。

现在成功了吗?未必。来看看下面这个使用同一个模式的例子,你就知道了:

<h[1-6]>.*?</h[1-6]>
在工具中查看
<body>
  <h1>玩转正则表达式教程</h1>
  欢迎来到正则表达式教程
  <h2>第一章 正则表达式入门</h2>
  正则表达式入门
  <h3>1.1 正则表达式的用途</h3>
  正则表达式的用途
  <h3>1.2 如何使用正则表达式</h3>
  如何使用正则表达式
  <h2>第二章 匹配单个字符</h2>
  匹配单个字符
  <h3>2.1 匹配普通文本</h3>
  匹配普通文本
  <h3>2.2 匹配任意字符</h3>
  匹配任意字符
  <h2>第三章 匹配一组字符</h2>
  匹配一组字符
  <h3>3.1 匹配多个字符中的某一个</h3>
  匹配多个字符中的某一个
  <h3>3.2 利用字符集合区间</h3>
  利用字符集合区间
  <h2>这是一个错误的标题</h3>
</body>

在这个例子里,原始文本里有一个标题是以<h2>开头、以<h3>结束的。这显然是一个不合法的标题,但它与我们所使用的模式匹配上了。

出现这种情况的根源是这个模式的第 2 部分(用来匹配结束标签的那个部分)对这个模式的第 1 部分(用来匹配开始标签的那个部分)毫无所知。要想彻底解决这个问题,就只能求助于回溯引用。

该内容基于 《正则表达式必知必会》 二度创作
转载请遵守原作者相关协议并注明本页地址
https://iamhefang.cn/tutorials/正则表达式/第八章-回溯引用/8.1-回溯引用有什么用