zoukankan      html  css  js  c++  java
  • 你真的理解正则修饰符吗?

    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

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

  • 相关阅读:
    KnockoutJS 3.X API 第五章 高级应用(4) 自定义处理逻辑
    KnockoutJS 3.X API 第五章 高级应用(3) 虚拟元素绑定
    KnockoutJS 3.X API 第五章 高级应用(2) 控制后代绑定
    KnockoutJS 3.X API 第五章 高级应用(1) 创建自定义绑定
    KnockoutJS 3.X API 第四章(14) 绑定语法细节
    KnockoutJS 3.X API 第四章(13) template绑定
    KnockoutJS 3.X API 第四章 表单绑定(12) selectedOptions、uniqueName绑定
    KnockoutJS 3.X API 第四章 表单绑定(11) options绑定
    KnockoutJS 3.X API 第四章 表单绑定(10) textInput、hasFocus、checked绑定
    KnockoutJS 3.X API 第四章 表单绑定(9) value绑定
  • 原文地址:https://www.cnblogs.com/humin/p/6927210.html
Copyright © 2011-2022 走看看