手摸手快速入门 正则表达式 进阶🛫


theme: channing-cyan
highlight: a11y-dark

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

正则表达式 进阶🛫

前言

推荐先阅读

再阅读本文。

本文主要讲解是关于 正则表达式 中,分组区间

1.分组

顾名思义就是将我们写的 正则字符或者数字 通过 () 进行包裹,合并组合在一起,然后进行 分组管理

那么每个 括号,代表一组。当然也称 捕获组

这就引出下面的两个概念 分组引用回溯引用

1.1 分组引用 $

既然我们通过 () 分组了,那么我们要做的肯定就是获取里面的值。

  • 获取值的方式为:RegExp.$number

可能上面讲的比较抽象,这里用大白话,理解一下

  • 从第一个括号出现,我们获取里面的值,就通过 RegExp.$1

  • 第二个括号,就是 RegExp.$2

  • … 以此类推

那你可能会有疑问?为什么不从下标 0 开始?有没有 RegExp.$0 这个东西?

  • 首先 RegExp.$0 这个是不存在的

  • 如果我们打印,得到的也只是 undefined

案例1

这里举个例子,我们来好好理解一下这个 分组引用

const string = '2022-11-05'
const string2 = '2022-11-06'
const reg = /(\d{4})-(\d{2})-(\d{2})/

reg.test(string) // true
reg.test(string2) // true

console.log(RegExp.$0)
console.log(RegExp.$1)
console.log(RegExp.$2)
console.log(RegExp.$3)

可以看到,我们分了 3 组,得到的结果值如下

image.png

看的这个结果,此时你可能会疑问,为什么它拿的最后一个,而不是第一个,这就有意思了!

  • 那我们将 stringstring2 反过来换个顺序再看一下

    const string = '2022-11-05'
    const string2 = '2022-11-06'
    const reg = /(\d{4})-(\d{2})-(\d{2})/
    
    reg.test(string2)
    reg.test(string)
    
    console.log(RegExp.$0)
    console.log(RegExp.$1)
    console.log(RegExp.$2)
    console.log(RegExp.$3)
    

    image.png

    可以看到确实拿的是最后一个

    说明 RegExp.$number 匹配到的是最新的值

  • 这里可以 再多做一个操作,来验证一下

        const string = '2022-11-05'
        const string2 = '2022-11-06'
        const reg = /(\d{4})-(\d{2})-(\d{2})/
    
        reg.test(string)
    
        console.log(RegExp.$0)
        console.log(RegExp.$1)
        console.log(RegExp.$2)
        console.log(RegExp.$3)
    
        reg.test(string2)
        console.log(RegExp.$0)
        console.log(RegExp.$1)
        console.log(RegExp.$2)
        console.log(RegExp.$3)
    

    image.png

    通过这个结果,我们可以更加确定,我们的结论 RegExp.$number的值 是 匹配到的是最新的值

  • 漏洞

    其实这个结论,目前看来并不是完全对,

    因为可以看到,上面都是匹配成功的,也就是说上面的例子 reg.test() 的值都是 true

    但是如果这个值为 false 结果又是什么?

    这里把 string2 的值进行修改

    const string = '2022-11-05'
    const string2 = '2022/11/06'
    const reg = /(\d{4})-(\d{2})-(\d{2})/
    
    reg.test(string)
    reg.test(string2)
    
    console.log(RegExp.$0)
    console.log(RegExp.$1)
    console.log(RegExp.$2)
    console.log(RegExp.$3)
    

    image.png

    可以看到结果是 string 的,所以我们的结论应该是

    • RegExp.$number的值 是 最近匹配成功 的值

    但是,也因此暴露出来一个问题,就是通过 RegExp.$number 这个方式来获取,是很不稳定。

  • 推荐

    最后,这里推荐各位小伙伴,确认了,只有匹配成功

    我们才去获取括号里面的值,去做相关的处理

      const string = '2022-11-05'
      const reg = /(\d{4})-(\d{2})-(\d{2})/
    
      if (reg.test(string)) {
        console.log(RegExp.$0)
        console.log(RegExp.$1)
        console.log(RegExp.$2)
        console.log(RegExp.$3)
      }
    

总结1

  • 通过 RegExp.$number 的方式来获取分组的值

  • 它匹配的是最近成功的结果值,然后存放起来。

  • 由于直接使用 RegExp.$number 来获取值,有点不稳定

    所以我们需要 reg.test() 判断成功后,再去执行某些操作

1.2 回溯引用 \

上面讲了 分组引用 $ 的使用

我们知道了,可以在 匹配成功后,通过 RegExp.$number 的方式,来获取到值。

那接下来,我们理解一下 回溯引用 \

疑问1

先抛出问题

  • 什么是 回溯引用 \

  • 它与 分组引用 $ 有什么区别呢?

  • 再或者说什么场景下,我会用到 回溯引用 \ 呢?

举个🌰

现在,有这么这么一个需求,小伙伴们先看下:

  • 例如,我想要将 连着重复的数字 找出来

    const str = 'wzms123,wzms11,wzms222,wzms3333,wwzzmmmssss'
    

    该怎么找?该怎么处理?

    难道用 for 循环,一个一个来?哇哦 😲

    我直接一个 达咩🙅🙅‍♂️

好了,下面我会通过这个需求,来慢慢讲解下 回溯引用 \

解答1

既然要找重复数字的,那么我们看图,直接分析这个字符串中,有哪些重复的!

image.png

可以看到有三处

那我们通过之前的知识,能够知道 元字符\d 是匹配数字的,那我们先试一下。

const str = 'wzms123,wzms11,wzms222,wzms3333,wwzzmmmssss'
const reg = /(\d)/g
const result = str.match(reg)

image.png

这里将所有的数字都匹配出来了。但我们想要重复!

此时观察下,我将 (\d) 通过 括号 包括起来了,说明 (\d) 是一个组,我们匹配到的值,将会放到这个组里面。

逻辑如下:

  • 遇到数字 (\d) 会进行匹配,然后把这个 数字值 放到

  • 那我们就只需要重复使用 这个组 中的值,就可以了

思路没问题,那用什么表示这个重复的值呢?

  • 那就用到我们的 回溯引用 \

  • 当然 回溯引用 \ 也有人喜欢叫 反向引用 \,看个人想叫什么都行。

来,那就针对上述问题,先写下代码,再解释

const reg = /(\d)\1/g

image.png

  • 对于出现的第一个括号 (\d) ,代表 第一组

  • \1 代表 第一组 所匹配到的值。

  • 一定要注意 回溯引用 \,它是用在 正则表达式 中的

那我们这里先简单总结下 回溯引用 \

写法:

  • 从第一个括号 () 出现,这个括号里面的值,通过 \1 来表示

  • 第二个括号 () 出现,则这个括号里面的值,通过 \2 来表示

  • 依次类推…

使用位置: 是用在 正则表达式 当中

处理这个问题

可以看到这个问题,其实并没有结束

我们这个结果并不符合我们的预想,我们想 333 这个值,是连续的,而不是断开的 3333

这就用到我们的 重复 +

const reg = /(\d)\1+/g

image.png

可以看到结果就是我们最开始的预期了,是不是很好用😄

案例2

对于上面的案例,只出现了一个 分组,这里再举个例子,来讲解多个 分组下,回溯引用 \ 的使用

针对下面字符串,找到

const str = 'wzms1212334545,wwzzmmmssss'
const reg = /(\d)\1/

2.区间 []

首先说一下 区间正则表达式中 的写法为 []

其次,区间 分为 几个 部分,包括 集合范围取反

区间 是较为复杂点点,因为里面的情况很多

  • 可以说 区间 里面的语法,相当于里面是一个全新的 正则表达式语法

    内心:😅😅😅

  • 不过深入理解后,其实还好!

不多说,一起来攻破它!

2.1 集合

这里通过🌰来讲解:

案例1

这里有四个字符串,判断 w字符 或者 z 的字符,是否在这个字符串内

const str1 = 'abc123' // false

const str2 = 'abcwe123' // true

const str3 = 'abcmn123' // false

const str4 = 'abc123zf' // true

如果不用正则表达式,则我们可能需要 String 类型的 includes 或者 indexOf 方法来判断,而且还得写两遍

而用 正则表达式,则只需一遍即可

const reg = /[wz]/g
reg.test(str)

image.png

可以看到是成功匹配的,那这个原理是什么呢?来详细分析下这个正则表达式

  • 可以看到 [] 包裹着 w字符 和 z字符

    • 其实代表的意思就是 这两个字符中的任意一个 wz,存在即可

案例2

通过面的案例可能不是很全,这里再来一个,可以更深入了解 区间集合

我想得到这样的 字符串: 好x你。可以是 好爱你好想你好烦你,其它的一律不可以。

const str1 = '好想你' // true

const str2 = '好像你' // false

const str3 = '好想爱你' // false

const str4 = '好爱你' // true

先分析下

  • 首先看到 第一个最后一个 字符是固定的

    • 则需要 ^$ 这两个元字符
  • 其次中间的值,可以为

通过上面的栗子,其实可以很快写出正则

const reg = /^好[爱想烦]你$/g

image.png

注意 第三个 好想爱你,它的结果是 null,这说明了什么。

  • 说明确实只会匹配 区间 内的字符一次,不会匹配多次的。
提高

好,我们这里成功完成,然后你正准备,拍桌子,下班,开溜🏃!

产品过来说,稍等一下,现在紧急又需要你支持第三个 好想爱你 这种,以及它们之间 两两结合

此时你的选择是:

  1. 摔桌子走人,谁爱干谁干
  2. 留下改代码

那当然是 打工人,打工魂😭😭

那我们快速处理下:

虽然看起来 两两组合,会比较烧脑,但是对于 正则 来说,很简单

const reg = /^好[爱想烦][爱想烦]?你$/g

image.png

可以看到非常成功就实现了,但是却不是很优雅

更优雅的为

const reg = /^好[爱想烦]{1,2}你$/g

2.2 范围

从上面知道了 集合 是什么之后,那么这个 范围 就很好理解了

就是 在某个 范围 里面,任意一个,存在即可

范围 是通过 - 字符来连接,当然这个也是在某些特殊情况下能代表 范围,常见的有下面几个

[a-z] // 代表的是小写字母a 到 小写字母 z
[A-Z] // 代表的是大写字母A 到 大写字母 Z
[0-9] // 代表的是数字 0 到 9

也可以进行组合

[a-f0-4] // 代表字符 abcdef01234
[a-zA-Z0-9] // 代表所有的字母和数字

这里还是通过例子来讲解

案例1

在一些网站中,需要我们在注册时,提供手机号,并且一般都会对我们的手机号做检验

  • 长度为 11 位 的 纯数字

  • 并且数字1作为开头

  • 第二位则是 3456789 中的任意一个

const str = '13839812345'
const reg = /^1[3-9][0-9]{9}/
reg.test(str) 

可以看到用 正则表达式 可以很快处理我们的这些问题

正好,这里也整个花里胡哨的 \d{8}

const str = '13839812345'
const reg = /^1[3-9]\d{9}/
reg.test(str) 

通过这个例子,我们可以看到 区间范围 的使用

2.3 取反

如果看过 手摸手快速入门 正则表达式 (基础)🛫 这篇文章,则知道什么是 取反 操作

当时说,会对 区间 进行 取反 操作

就是到这里,下面讲解下

  • 取反 是字符 ^ 标识,并且最主要的是,只有它在 区间开头 才能表示 取反 操作

  • 例如 /[^abc123]/

    • 上面这个表达式的意思,就是 匹配除了 a、b、c、1、2、3 之外的任意字符

    那你猜猜,能不能匹配到 ^ 字符呢?

    • 结果是能匹配到的
  • 例如 /[^0-9]//[^\d]/

    • 表示 能够匹配数字以外任意字符,与 \D 的作用一样。
  • /[abc^123]/ 则不会代表 取反 的意思

      const reg = /[abc^123]/
      const str = '1'
      const str = '^'
      reg.test(str) // true
      reg.test(str2) // true
    

2.4 转义

我们知道 转义 字符是通过 \ 来表示

而对于 区间 里面出现的字符,绝大多数都只是普通形式

  • 例如 /[.+?()]/

    代表的仅仅只是字符 .、+、?、(、) 这个字符本身

  • 我发现的 特殊的需要 转义 的字符有 2 个, ]、\,而且这两个还有不同,我们看下

    • 在对 ] 进行匹配时

      const reg = /[123\]]/
      const str = ']'
      reg.test(str) // true
      
    • 在对 \ 进行匹配时,则需要两个 \\

      const reg = /[123\\]/
      const str = '\\'
      reg.test(str) // true
      

3. () [] {} 区别

由于 () [] {} 这三个符号,很容易混淆,所以这里,再对这三个符号,做一次汇总,就能够完全了解了。

()

() 代表分组,每一个组,里面都是一个小的 正则表达式

它有两个大块,分组引用回溯引用

  • 通过 RegExp.$number 来获取值

  • 通过在 正则表达式 中使用 \number 来获取每个 分组 里面,所匹配到的值

[]

[] 代表 区间,匹配某个字符,是否在这个 中括号区间 里,只要存在即可匹配成功

它拥有 集合、范围、取反、转义 几大部分

{}

{} 代表 重复,代表重复几次

可以是单个数字 {5} 代表重复5次

也可以是范围 {5,10} 代表可以重复 5 到 10 次

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

昵称

取消
昵称表情代码图片

    暂无评论内容