一聚教程网:一个值得你收藏的教程网站

热门教程

正则表达式中?=、?!、?<=、?<!、?:的理解与应用举例实用指南

时间:2026-08-31 16:00:02 编辑:袖梨 来源:一聚教程网

平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“正则表达式中?=、?!、?<=、?<!、?:的理解与应用举例”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。

一、?=、?!、?<=、?<!、?:的解释

1. 先看一下比较官方的解释

  • (?=pattern):正向先行断言,表示匹配位置后面必须紧跟着满足 pattern 的字符串,但不包括这个字符串在匹配结果中。
  • (?!pattern):负向先行断言,表示匹配位置后面不能紧跟着满足 pattern 的字符串,也不包括这个字符串在匹配结果中。
  • (?<=pattern):正向后行断言,表示匹配位置前面必须是满足 pattern 的字符串,但不包括这个字符串在匹配结果中。
  • (?<!pattern):负向后行断言,表示匹配位置前面不能是满足 pattern 的字符串,也不包括这个字符串在匹配结果中。
  • (?:pattern):非捕获型分组,表示将 pattern 包含在一个分组中,但不把这个分组的匹配结果保存到分组编号中。这个分组通常用来表示可选的或重复的子表达式,或者是限制量词的作用范围,而不需把它们的匹配结果单独提取出来。

2. 再看一下比较通俗易懂的解释:

  • RegExp1(?=RegExp2) 匹配后面是RegExp2 的 RegExp1
  • RegExp1(?!RegExp2) 匹配后面不是RegExp2 的 RegExp1
  • (?<=RegExp2)RegExp1 匹配前面是RegExp2 的 RegExp1
  • (?<!RegExp2)RegExp1 匹配前面不是RegExp2 的 RegExp1
  • (?:RegExp) 这个等下单独解释,与上面的不太一样

在这个场景下,是不是有点明白了,其实?=、?!、?<=、?<!的意思能够理解为 if 判断,即只有先借助它们(RegExp2)的判断之后,才能够拿到到正则(RegExp1)的匹配结果。

3. 零宽度断言

?=、?!、?<=、?<!其实就是正则表达式中的零宽度断言,以上面的举例来解释↓

理解这一步时,RegExp2匹配到的内容是不会得到的,也不会消耗匹配到的字符,只会得到RegExp1的匹配结果,这就是零宽度断言,零宽度断言在正则表达式中很有用,因为它们能够在不改变匹配结果的情况下,对匹配位置前后的内容进行限制或判断。

4. ?: 的解释

在这个场景下,(?:) 同时不是零宽度断言,而是非捕获组,它跟普通的括号 () 的区别在于,它不会保存匹配到的内容,但是它仍然会消耗字符并得到匹配内容,只是不会保存匹配结果。

  • 结合项目来看,()表示捕获分组,它会把匹配到的内容保存到内存中,开发者能够采用$n(n是一个数字)来代表第n个()中匹配到的内容
  • 落到代码里,(?:)表示非捕获组,它匹配的内容不会被保存,所以无法采用$n拿到,但也因为没有被保存所以节省了一部分内存空间

二、举例

?=

'我喜欢苹果'.replace(/我喜欢(?=苹果)/,'我讨厌') // 匹配 我喜欢苹果 中的 我喜欢 并替换为 我讨厌,因为是零宽度断言所以不包含苹果,故结果为 我讨厌苹果
'我喜欢橘子'.replace(/我喜欢(?=苹果)/,'我讨厌') // 我喜欢后面不是苹果,所以这里正则未通过,匹配不到任何内容,故结果仍为 我喜欢橘子

?!

'我喜欢苹果'.replace(/我喜欢(?!苹果)/,'我讨厌') // 匹配后面不是苹果的我喜欢,正则未通过,故结果仍为 我喜欢苹果
'我喜欢橘子'.replace(/我喜欢(?!苹果)/,'我讨厌') // 正则通过,匹配到 我喜欢 进行替换,因为是零宽度断言所以橘子不在匹配结果中,故结果为 我讨厌橘子

?<=

'我喜欢苹果'.replace(/(?<=我喜欢)苹果/,'西红柿') // 匹配到 苹果 ,故结果为 我喜欢西红柿
'我喜欢橘子'.replace(/(?<=我喜欢)苹果/,'西红柿') // 匹配不通过,故结果仍为 我喜欢橘子

?<

'我讨厌苹果'.replace(/(?<!我喜欢)苹果/,'西红柿') // 匹配到 苹果 ,故结果为 我讨厌西红柿
'我喜欢苹果'.replace(/(?<!我喜欢)苹果/,'西红柿') // 匹配不通过,故结果仍为 我喜欢苹果

?:

'hello world'.replace(/(?:hello) (world)/,'$1') // 匹配内容为hello world,但是hello并没有被保存,因此$1取的是world,故结果为world

三、特殊情况

结合项目来看,正则平时我们很少会自己写,一般都是复制别人的~~~(别人的才是最好的)。随后就经常看到一种写法,比如:

/(?=.*[A-Z])[A-Za-z]{5,10}/

落到代码里,这时候可能有些人就想,咦,(?=)不都是符合条件后匹配它前面的内容吗?这里为什么能放在开头 呢,他前面没内容啊?其实大家能够这么理解,当(?=)前面没有内容,或者说(?=)被放在正则开头采用时,(?=)的作用就相当于检索全部内容是否符合它的要求,如果不符合也就没必要继续向后匹配了,这就很像if判断,只有当条件为true时,才能执行后面的内容。

所以这里的正则意为:先检查内容中是否至少包含一个大写字母,如果有,则继续检查同时匹配5~10个大小写字母,将这5~10个大小写字母作为结果得到。

四、实例应用

姓名脱敏(添加*号)

'李小龙'.replace(/(?<=[u4e00-u9fa5])[u4e00-u9fa5]/g, '*') // 李**

手机号/银彳账号脱敏

'13912345678'.replace(/(?<=d{3})d(?=d{3})/g, '*') // 139*****678

强密码规则校验

// 密码不能为空,8-30位,至少包含一个大写字母、小写字母、数字、特殊字符
/^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[W_])(?!.*[u4e00-u9fa5])(?!s)[a-zA-Z0-9W_]{8,30}$/

“?”的几种用法

  • “?”元字符规定其前导对象必须在目标对象中连续出现零次或一次。
  • 实际处理时,当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。比如,对于字符串“oooo”,“o+?”将匹配单个“o”,而“o+”将匹配所有“o”。
  • 从实现思路看,(?:pattern) ——匹配pattern但不拿到匹配结果,也就是说这是一个非拿到匹配,不进行存储供以后采用。这在采用或字符“(|)”来组合一个模式的各个部分是很有用。比如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。
  • 理解这一步时,(?=pattern)——正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非拿到匹配,也就是说,该匹配不需拿到供以后采用。比如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
  • 实际处理时,(?!pattern)——正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非拿到匹配,也就是说,该匹配不需拿到供以后采用。比如“Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始
  • 落到代码里,(?<=pattern)——反向肯定预查,与正向肯定预查类拟,只是方向相反。比如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。
  • 理解这一步时,(?<!pattern)——反向否定预查,与正向否定预查类拟,只是方向相反。比如“(?<!95|98|NT|2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”。
  • (?i)——该表达式右边的字符忽略大小写
  • (?-i)——该表达式右边的字符区分大小写
  • (?i:x)——x 忽略大小写
  • (?-i:x)——x 区分大小写
  • 实际处理时,?和懒惰匹配——尽可能少的匹配,比如:源字符串str=“dxxddxxd”中,dw*?会匹配 dx,而dw*?d会匹配 dxxd。

总结

到此这篇关于正则表达式中?=、?!、?<=、?<!、?:的理解与应用举例的文章就介绍到这了,更多相关正则表达式?=、?!、?<=、?<!、?:内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多兼容脚本之家!

您可能感兴趣的文章:
  • idea 正则表达式搜索替换应用详解
  • 详解Linux中正则表达式的应用
  • JavaScript中正则表达式的概念与应用
  • 关于正则表达式基本语法的应用详解(必看篇)
  • php正则表达式基本知识与应用详解【经典教程】
  • 正则表达式性能优化方法(高效正则表达式书写)
  • 正则表达式高级应用与性能优化记录

热门栏目