正则表达式分组、断言详解

正则表达式分组、断言详解

正则表达式分组,断言详解

参考

举个例子

比如要抓取到 html 源码里的 <title>xxx</title>, 里面的 xxx。按照基本的操作,只能 <title> .*</title> 而这样写匹配出来的是完整的<title>xxx</title>标签,并不是单纯的页面标题 xxx。

想解决以上问题,就要用到断言知识。

在讲断言之前,读者应该先了解分组,这有助于理解断言。

分组在正则中用()表示,分组的作用有两个:

  • 将某些规律看成是一组,然后进行组级别的重复,可以得到意想不到的效果。
  • 分组之后,可以通过后向引用简化表达式。

继续举例子

在匹配 ip 地址时,我们可以这样写

1
\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}

发后面重复,利用分组,我们可以这样简写

1
\d{1,3}(.\d{1,3}){3}

然后我们再利用分组的做法,优化哈上个例子

普通写法

1
<title>.*</title>

使用分组简写

1
<(title)>.*</\1>

说明:这里 \1反向引用 其实是引用了第一个括号中里也就是第一个分组里的文本内容。整正则式子默认为第 0 组,而第一个小括号扩住的分组就是第一组,依次类推。通过 \index 引用某组的文本内容, 切记 引用的不是正则表达式,而是匹配的文本结果

然后我们再使用反向引用,来匹配哈上面的 ip 地址

简化后如下

1
(\d{1,3})(.\1){3}

解释:把 \d{1,3} 成组,, 再通过 \1 引用该分组,在对此引用连续匹配 3 次。

但是这样写是错误的 ❌

这样匹配的 ip 每一段都是相同的,比如 123.123.123.123

因为 后向引用,引用的仅仅是文本内容,而不是正则表达式!

然后继续说 断言

所谓断言,多用于匹配,没有什么规律的文本,通过匹配他的前后文,反推出它来。

即通过判断 需匹配文本 的前边或后边,将会出现满足某种规律的字符串。**并且断言只是条件,帮你找到真正需要的字符串,本身并不会匹配!也没有编号,所以不能用来后向引用**
符号描述
?=正先行断言-存在
?!负先行断言-排除
?<=正后发断言-存在
?<!负后发断言-排除
就拿文章开篇的例子来说,我们想要的是xxx,它没有规律,但是它前边肯定会有`<title>`,后边肯定会有`</title>`,这就足够了。

想指定 xxx 前肯定会出现<title>,就用正后发断言,表达式:(?<=<title>).*

向指定 xxx 后边肯定会出现</title>,就用正先行断言,表达式:.*(?=</title>)

两个加在一起,这样就能匹配到 xxx。

1
(?<=<title>).*(?=</title>)

无论正先行断言还有正后发断言,都是相对需匹配的文本(上文的 xxx)判断的。

也就是说,断言的名称,正先行还是正后发,即是相对匹配目标而定的。

如果匹配目标后边有条件,也就是目标字符串在前,即使用正先行断言 ?=

如果匹配目标前边有条件,也就是目标字符串在后,即使用正后发断言 ?<=


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!