• 你真的理解正则修饰符吗?


    0、前言

    一段代码引发的思考:

    var r = /d/g;
    console.log(r.test('1'));
    console.log(r.test('1'));
    console.log(r.test('2'));
    console.log(r.test('2'));
    

    先看看如上的代码,不要执行,自己先猜测下结果。

    1、正则修饰符

    正则在各个语言中,实现的标准并不完全一致。我们这里就讨论在 JavaScript 中的实现。

    JavaScript 中,正则有四个修饰符: global, ignoreCase, multiline, unicode,详细请参考:MDN RegExp

    它们的含义如下:

    • global(g) 针对字符串中所有可能的匹配来测试正则表达式
    • ignoreCase(i) 匹配时忽略大小写
    • multiline(m) 多行输入将被视为多行(此时开始^和结尾匹配$可以在每行中进行匹配)
    • unicode(u) 对字符串采用unicode进行匹配

    修饰符:i

    i 比较易懂,在匹配的时候会忽略大小写,示例如下:

    var text = 'abc';
    var r = /abc/;
    console.log(r.test('abc')); // true
    console.log(r.test('Abc')); // false
    r = /abc/i;
    console.log(r.test('abc')); // true
    console.log(r.test('Abc')); // true
    

    修饰符:m

    当匹配多行时,默认是全文本匹配,使用 m 之后,将对每一行进行单独匹配。

    // 定义一个多行文本
    var text = `a b c
    
    A B C`;
    var r = /c$/; // 匹配以C结尾的文本
    console.log(r.test(text)); // false 全文本匹配,匹配不上
    r = /c$/m;
    console.log(r.test(text)); // true 多行匹配,c是第一行的末尾,匹配成功
    

    修饰符:u

    使用修饰符 u,将采用 Unicode 模式进行匹配,必须要在正则中包含unicode才能看到效果:

    var r = /u{61}/; // 匹配61次u字符
    console.log(r.test('a')); // false, 明显匹配不上
    r = /u{61}/u; // Unicode模式,u{61} = 'a'
    console.log(r.test('a')); // true, Unicode下能匹配
    r = /u{61}{3}/u; // 匹配3个a,注意正则写法
    console.log(r.test('aaa')); // true
    

    注意:在/u模式下,正则中 u 是一个整体,不可拆分。

    2、正则修饰符:g

    接下来,进入本文的重点,修饰符 g 的匹配模式。

    首先,我们先回到开头的那段代码,我想大部分人的答案可能是:true true true true 吧。

    实际上,正确答案是:true false true false,是不是觉得不可思议?接着往下看。

    RegExp.prototype.test()

    RegExp.prototype.test() 方法的逻辑是:当找到第一个匹配项时,返回 true。查找整个字符串都没有找到匹配项,返回 false

    那具体又是如何查找的呢?这里我们就要看 RegExp 的另外一个方法了:RegExp.prototype.exec()

    注意观察这个方法的返回值:

    var r = /d/;
    // 注意看,返回值是一个数组,除了匹配到的元素之外,还有一个 index 属性
    console.log(r.exec('123')); // ["1", index: 0, input: "123"]
    

    关键就是 exec 返回值中的 index 属性,这个属性标识从输入文本的哪一个索引处开始查找匹配项。

    如果不加 g,每次都是从索引0处开始查找。

    var r = /d/;
    console.log(r.exec('123')); // ["1", index: 0, input: "123"]
    console.log(r.exec('123')); // ["1", index: 0, input: "123"]
    console.log(r.exec('123')); // ["1", index: 0, input: "123"]
    

    那如果加 g 呢?

    var r = /d/g;
    console.log(r.exec('123')); // ["1", index: 0, input: "123"]
    console.log(r.exec('123')); // ["2", index: 1, input: "123"]
    console.log(r.exec('123')); // ["3", index: 2, input: "123"]
    console.log(r.exec('123')); // null
    

    从结果我们可以看出,这个 index 是在变化的,当找不到匹配项时,会返回 null。

    总结一下:修饰符 g 的作用,是标识是否需要全局存储这个index。

    有了这个理解,那么回到之前的问题,那就说得通了。我们使用了 g 修饰符,那么会存储上一次的 index,当执行第二次 console.log(r.test('1')); 时,索引为1,当然就匹配不上了,所以就返回了 false

    那问题又来了,为什么第三次,又返回了 true 呢?

    还是先看代码:

    var r = /d/g;
    console.log(r.exec('12')); // ["1", index: 0, input: "12"]
    console.log(r.exec('12')); // ["2", index: 1, input: "12"]
    console.log(r.exec('12')); // null
    console.log(r.exec('12')); // ["1", index: 0, input: "12"]
    

    当发现已经匹配不上元素时,会将这个 index 重新设置为 0

    这也就解释了最开始的整个代码。

  • 相关阅读:
    用于展现图表的50种JavaScript库
    EditPlus常用正则表达式
    人工智能生成仿真人脸
    树莓派搭建SVN服务器
    JS三座大山再学习 ---- 异步和单线程
    JS三座大山再学习 ---- 作用域和闭包
    基于C#的MongoDB数据库开发应用(2)--MongoDB数据库的C#开发
    基于C#的MongoDB数据库开发应用(1)--MongoDB数据库的基础知识和使用
    大数据高效复制的处理案例分析总结
    基于DevExpress的Winform程序安装包的制作
  • 原文地址:https://www.cnblogs.com/humin/p/6927210.html
Copyright © 2020-2023  润新知