手摸手快速入门 正则表达式 (高级)🛫


theme: channing-cyan
highlight: a11y-dark

本文正在参加「金石计划 . 瓜分6万现金大奖」

正则表达式 高级🛫

前言

推荐先阅读

再阅读本文。

本文主要讲解是关于 正则表达式 中,断言贪婪和惰性

1. 断言

断言,我个人认为是非常强的,非常的 NB

但是,依然记得,在最开始接触 断言,我都不想看,难懂是一方面,再加上网上其他文章的复杂解释,各种名词,各种乱七八糟,差点都给我劝退了。😅

下面我们来理解下 断言

首先 断言 也可以称为 环视 或者 零宽断言

  • 记住 这两个词,至关重要

  • 环视 的意思,就是 环顾四周,对于 正则表达式 而言,就是

    • 表达式 中的 某个位置 处,看看左边看看右边
  • 零宽断言 先不着急,我会放到下面讲解。

下面放出 百度百科 截图,因为我觉得说的还是很在理的。

image.png

意思很明确,就是程序在执行到 断言 位置,就会去进行判断,判断是否符合条件

  • 相当于我们执行 js 中遇到 if 条件了

好,这就到我们第一个阶段,程序遇到 断言

  • 之后进行判断,也就是所谓的 环视 状态

1.1 环视

假设 下面这一段是我们的 正则表达式 (没有任何含义,主要是用来举例)

  • / aaaa bbbb cccc dddd eeee ffff gggg /

我们设置 dddd 为我们的 断言 位置

image.png

程序执行,遇到 断言,进入 环视 状态,如下图

image.png

环视 状态时,会 看看左边看看右边

  • 而事实上,则只选择看一个方向

    • 要么选择 看左边 的代码

    • 要么选择 看右边 的代码

由于只能选择一个方向

那么自然引出,两个名词 先行断言后行断言

1.2 先行,后行

从上面我们知道,遇到 断言 处,只能看一个方向,要么 左边,要么 右边

那这里我们定义下

  • 看左边时,叫 后行 断言

  • 看右边 时,则叫 先行 断言

但是呢

无论是 先行断言 还是 后行断言,在所谓的 环视 完毕后

都要做出判断,知道它 是否匹配,是否符合条件

而下一个步骤则是,与大多数判断条件相同,还判断是否有 是否取反 的操作

这就引出我们下面的 正向反向 的概念了

1.3 正向,反向

取反 操作,则对应下面的名词

  • 取反反向

  • 没有 取反 则叫 正向

在了解什么是 取反

取反 在与上面的 先行断言后行断言 两两结合

就引出我们 断言 的 真正的 种情况,

也是我们经常在网上能够看到的名称

1.4 断言 的四种情况

通过上面的概念,再进行 两两结合,则得出下面真正的 断言

有四种

  • 正向 先行 断言

    • 含义:在 断言 位置处,向 右边 看表达式,匹配成功则成功,匹配失败则失败
  • 正向 后行 断言

    • 含义:在 断言 位置处,向 左边 看表达式,匹配成功则成功,匹配失败则失败
  • 反向 先行 断言

    • 含义:在 断言 位置处,向 右边 看表达式

      • 匹配 成功取反操作后,则代表 失败

      • 匹配 失败取反操作后,则代表 成功

  • 反向 后行 断言

    • 含义:在 断言 位置处,向 左边 看表达式

      • 匹配 成功取反操作后,则代表 失败

      • 匹配 失败取反操作后,则代表 成功

至此

断言 情况下,它们的 含义 被搞清楚了。

可以看到,这些名词真的是一大堆

要是不准备充分,直接上去莽 断言,劝退不知无数次😵

u=1830830853,1165056070&fm=253&fmt=auto&app=138&f=JPEG.webp

1.5 写法

在上面,终于是把 断言 中,大部分的概念性名词 和 含义,理解透了!

下面进行写法研究

1.5.1 正向,反向 写法

我们写 js 都知道,在 if 条件中

  • 相等 用 ===

  • 不相等 用 !==

取反 操作,与上面很类似

  • 正向=

  • 反向!

1.5.2 先行,后行 写法

  • 默认就是 先行,无符号 表示

  • 后行,则用 < 符号,来表示

1.5.3 断言 四种写法

当然,断言 肯定也是有特殊写法,好让我们从 正则表达式 中一眼就能看出

断言写法: (?xy表达式)

  • x 代表 先行 还是 后行

  • y 代表 正向 还是 反向

故 最终 四大情况的写法如下

  • 正向 先行 断言 写法:(?=表达式)
  • 正向 后行 断言 写法:(?<=表达式)
  • 反向 先行 断言 写法:(?!表达式)
  • 反向 后行 断言 写法:(?<!表达式)

1.6 零宽断言

上面讲解了 断言 的 概念 和 写法

接下来说一下 为什么 断言 也称 零宽断言

零宽 这个名词,又代表了什么含义

1.6.1 案例1

这里举个例子:

const str1 = '我爱喝旺仔牛奶'
const str2 = '我是旺仔米苏呀'
const str3 = '我是旺仔'
const str4 = '我是旺仔哟'
const str5 = '我是米苏'
const str6 = '我是米苏哟'

这里有 6 个字符串

  • 需求:我想要找到里面存在 旺仔 两个字的字符串

那你可能会有 N 种方法来处理,这里用 正则方法 简单写下

const reg = /旺仔/g

image.png

当然上面这个需求很简单,如果此时,再给你一个新的需求:

  • 想要找到里面存在 旺仔 两个字,并且后面也必须跟上 米苏,这两个字 的字符串,才能成功
const reg = /旺仔(?=米苏)/g

因为是看后边,并且确认必须是 米苏, 所以我们使用的是, 正向先行断言 的方式来处理

image.png

可以明显看到,只有 str2 匹配成功,但是你看结果,并没有将 米苏 这两个字匹配出来。

这就是 断言 为什么称为 零宽断言

因为它仅仅只是看,查看是否符合条件,但是呢,它并不会将匹配结果给出来。

补充

其实,上面的案例讲的很清楚了

这里再扩充一下额外的知识点:

好,在你准备干完活,准备下班!

产品:请留步,我想知道 下面这个字符串是否能够匹配成功?

const str8 = '我是旺仔哟,不是米苏哟'

答案是 不成功

原因很简单,是因为我们上面 正则表达式的 写法,肯定是 旺仔 后面紧紧跟着 米苏 这两个字,才能成功

而如果想要成功匹配上面这个字符串,

  • 也就是只要 旺仔 后面 出现了 米苏 这两个字,就能成功

    则需要修改我们的 正则表达式

    const reg = /旺仔(?=.*米苏)/g
    
  • 只需要 米苏 前面添加 .*,它代表的含义为:

    米苏 前面出现 任意字符出现 零次多次

即可匹配成功!

1.7 总结

最后简单总结下 断言

断言 称为 环视零宽断言

有四种情况 以及 写法

  • 正向 先行 断言 写法:(?=表达式)
  • 正向 后行 断言 写法:(?<=表达式)
  • 反向 先行 断言 写法:(?!表达式)
  • 反向 后行 断言 写法:(?<!表达式)

其实很多场景下,用 断言 来处理特别简单

  • 密码强度,必须有 大写字母,小写字母,数字,特殊符号

  • 数字格式化(千位分隔符)

1.8 额外补充: ?:

这里再讲一个容易与上面 断言 混淆的,(?:表达式)

首先说明一下,这个不是 断言

而是 分组 中的 非捕获分组,它并不会将匹配的结果保存下来

也就是,

  • 我们无法通过 \1 进行 回溯引用

  • 也无法通过 $1 来获取值

注意写法,千万别和上面的 断言 混淆了

2. 贪婪 和 惰性

手摸手快速入门 正则表达式 (基础)🛫 这篇文章中,我们知道了 正则表达式重复 的方式

而上面所有的 重复,其实都是 贪婪 模式

什么是 贪婪

  • 通过字面意思,我们可以知道,它会尽可能匹配多的值

这里贴一下相关字符

image.png

贪婪 相对的,则是 惰性,也称为 非贪婪

  • 惰性 匹配,则会匹配较少的值

它的写法,则是上面的 所有字符 后面添加 ?,即可成为 惰性

即:

*?
+?
??
{n}?
{n,}?
{min,max}?

可以看到还是很简单,能够容易就能够理解的

2.1 案例1

这里再举个例子,来深入了解下 贪婪惰性

给定一段字符串,我想要找到 旺仔 之间的内容

const str = '我是旺仔米苏号,我是0号'
const str1 = '我是旺仔1号,米苏1号'
const str2 = '我是旺仔12号,米苏12号'
const str3 = '我是旺仔123号,米苏123号'
  • 贪婪

    const reg = /旺仔(.*)号/g
    

    上面这种写法就是 贪婪 模式,可以看到没有 ? 出现,来看下得到的结果

    image.png

    可以看到 贪婪 模式下,会匹配到更多值

  • 惰性

    看下 惰性 能够匹配到的值

    const reg = /旺仔(.*?)号/g
    

    image.png

这样可以明显看到 它们之间的区别

2.2 案例2

上面的案例,虽然体现了 惰性,但是因为后面有一个 的影响,导致它必须匹配到 字,才能结束

如果我们把例子修改下,把 取消掉,只提取,旺仔 后面的值

则你会发现,惰性 是真的懒🤣

  • 贪婪

    const reg = /旺仔(.*)/g
    

    image.png

    可以看到 贪婪 会将后面,所有的值,全部拿到

  • 惰性

    const reg = /旺仔(.*?)/g
    

    image.png

    惰性,则直接匹配空字符串🤣

2.3 案例3

这里再对上面的案例进行修改,相信这个就能够完全理解了

旺仔 开始,到匹配到 数字 后结束

  • 贪婪

    const reg = /旺仔.*\d/g
    

    image.png

    可以看到 贪婪 会匹配到更多的数字

  • 惰性

    const reg = /旺仔.*?\d/g
    

    image.png

    惰性,则直接匹配到数字就结束了!

总结

通过上面 3 个案例,相信可以很清楚的了解了 贪婪惰性 的区别

默认的,基础的 重复 字符 就是 贪婪

惰性,则在 基础的 重复 字符的后边,添加 ? 字符,就变为 惰性

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容