美文网首页
正则表达式

正则表达式

作者: 释梦石 | 来源:发表于2020-08-31 10:38 被阅读0次

    正则表达式概述

    正则表达式(regular expression)是一种表达文本模式(即字符串结构)的方法,有点像字符串的模板,常常用来按照“给定模式”匹配文本。比如,正则表达式给出一个 Email 地址的模式,然后用它来确定一个字符串是否为 Email 地址。

    正则表达式的作用

    1. 给定的字符串是否符合正则表达式的过滤逻辑(匹配)
    2. 可以通过正则表达式,从字符串中获取我们想要的特定部分(提取)
    3. 强大的字符串替换能力(替换)
    正则表达式的特点
    1. 灵活性、逻辑性和功能性非常的强
    2. 可以迅速地用极简单的方式达到字符串的复杂控制

    创建一个正则表达式

    1. 使用字面量以斜杠表示开始和结束

    var regex = /xyz/;
    

    2. 另一种是使用RegExp构造函数

    var regex = new RegExp('xyz');
    

    上面两种写法是等价的,都新建了一个内容为xyz的正则表达式对象。它们的主要区别是,第一种方法在引擎编译代码时,就会新建正则表达式,第二种方法在运行时新建正则表达式,所以前者的效率较高。而且,前者比较便利和直观,所以实际应用中,基本上都采用字面量定义正则表达式。

    RegExp构造函数还可以接受第二个参数,表示修饰符,如,

    var regex = new RegExp('xyz', 'i');
    // 等价于
    var regex = /xyz/i;
    

    修饰符

    修饰符(modifier)表示模式的附加规则,放在正则模式的最尾部。
    修饰符可以单个使用,也可以多个一起使用。

    // 单个修饰符
    var regex = /test/i;
    
    // 多个修饰符
    var regex = /test/ig;
    

    g 修饰符

    默认情况下,第一次匹配成功后,正则对象就停止向下匹配了。g修饰符表示全局匹配(global),加上它以后,正则对象将匹配全部符合条件的结果,主要用于搜索和替换。正则模式不含g修饰符,每次都是从字符串头部开始匹配.正则模式含有g修饰符,每次都是从上一次匹配成功处,开始向后匹配

    var regex = /b/g;
    var str = 'abba';
    regex.test(str); // true
    regex.test(str); // true
    regex.test(str); // false
    

    i修饰符

    正则对象区分字母的大小写,加上i修饰符以后表示忽略大小写(ignoreCase)加了i修饰符以后,不考虑大小写。

    m 修饰符

    m修饰符表示多行模式(multiline),会修改和$的行为。默认情况下(即不加m修饰符时),^和$匹配字符串的开始处和结尾处,加上m修饰符以后,还会匹配行首和行尾,即^和会识别换行符(\n)。

    /world$/.test('hello world\n') // false
    /world$/m.test('hello world\n') // true
    

    上面的代码中,字符串结尾处有一个换行符。如果不加m修饰符,匹配不成功,因为字符串的结尾不是world;加上以后,$可以匹配行尾。

    正则表达式实例方法

    RegExp.prototype.test()

    正则实例对象的test方法返回一个布尔值,表示当前模式是否能匹配参数字符串。

    /cat/.test('cats and dogs') // true
    

    如果正则表达式带有g修饰符,则每一次test方法都从上一次结束的位置开始向后匹配

    var r = /x/g;
    var s = '_x_x';
    
    r.lastIndex // 0
    r.test(s) // true
    
    r.lastIndex // 2
    r.test(s) // true
    
    r.lastIndex // 4
    r.test(s) // false
    

    上面代码的正则表达式使用了g修饰符,表示是全局搜索,会有多个结果。接着,三次使用test方法,每一次开始搜索的位置都是上一次匹配的后一个位置。
    注意,带有g修饰符时,正则表达式内部会记住上一次的lastIndex属性,这时不应该更换所要匹配的字符串,否则会有一些难以察觉的错误。

    var r = /bb/g;
    r.test('bb') // true
    r.test('-bb-') // false
    

    RegExp.prototype.exec()

    正则实例对象的exec()方法,用来返回匹配结果。如果发现匹配,就返回一个数组,成员是匹配成功的子字符串,否则返回null。

    var s = '_x_x';
    var r1 = /x/;
    var r2 = /y/;
    r1.exec(s) // ["x"]
    r2.exec(s) // null
    

    如果正则表达式包含圆括号(即含有“组匹配”),则返回的数组会包括多个成员。第一个成员是整个匹配成功的结果,后面的成员就是圆括号对应的匹配成功的组。也就是说,第二个成员对应第一个括号,第三个成员对应第二个括号,以此类推。整个数组的length属性等于组匹配的数量再加1。
    exec()方法的返回数组还包含以下两个属性:

    1. input:整个原字符串。
    2. index:模式匹配成功的开始位置(从0开始计数)。
    var r = /a(b+)a/;
    var arr = r.exec('_abbba_aba_');
    arr // ["abbba", "bbb"]
    arr.index // 1
    arr.input // "_abbba_aba_"
    

    利用g修饰符允许多次匹配的特点,可以用一个循环完成全部匹配。

    var reg = /a/g;
    var str = 'abc_abc_abc'
    
    while(true) {
      var match = reg.exec(str);
      if (!match) break;
      console.log('#' + match.index + ':' + match[0]);
    }
    // #0:a
    // #4:a
    // #8:a
    

    上面代码中,只要exec()方法不返回null,就会一直循环下去,每次输出匹配的位置和匹配的文本。

    正则实例对象的lastIndex属性不仅可读,还可写。设置了g修饰符的时候,只要手动设置了lastIndex的值,就会从指定位置开始匹配。

    字符串方法

    String.prototype.match()

    字符串实例对象的match方法对字符串进行正则匹配,返回匹配结果。默认情况下,match()方法只会找到第一个符合要求的内容,找到以后就停止检索。我们可以设置正则表达式为全局匹配模式,这样就会匹配到所有的内容,并以数组的形式返回。

    var str = "1a2a3a4a5e6f7A8B9C";
    
        var result1 = str.match(/[a-z]/);   // 找到符合要求的第一个内容,然后返回
        var result2 = str.match(/[a-z]/g);  // 设置为“全局匹配”模式,匹配字符串中 所有的小写字母
        var result3 = str.match(/[a-z]/gi); // 设置多个匹配模式,匹配字符串中 所有的字母(忽略大小写)
    
        console.log(result1); // 打印结果:["a"]
        console.log(result2); // 打印结果:["a", "a", "a", "a", "e", "f"]
        console.log(result3); // 打印结果:["a", "a", "a", "a", "e", "f", "A", "B", "C"]
    

    String.prototype.search()

    字符串对象的search方法,返回第一个满足条件的匹配结果在整个字符串中的位置。如果没有任何匹配,则返回-1。search()方法可以接受一个正则表达式作为参数,然后会根据正则表达式去检索字符串。serach()只会查找第一个,即使设置全局匹配也没用。

    var str = "hello abc hello aec afc";
        /*
        * 搜索字符串中是否含有abc 或 aec 或 afc
        */
        result = str.search(/a[bef]c/);
        console.log(result); // 打印结果:6
    

    String.prototype.replace()

    字符串对象的replace方法可以替换匹配的值。它接受两个参数,第一个是正则表达式,表示搜索模式,第二个是替换的内容。

    str.replace(被替换的内容, 新的内容)
    

    参数解释:

    1. 被替换的内容:可以接受一个正则表达式作为参数。
    2. 新的内容:默认只会替换第一个。如果需要替换全部符合条件的内容,可以设置正则表达式为全局匹配模式。
     //replace()方法:替换
        var str2 = "Today is fine day,today is fine day !!!"
    
        console.log(str2);
        console.log(str2.replace("today","tomorrow"));  //只能替换第一个today
        console.log(str2.replace(/today/gi,"tomorrow")); //这里用到了正则,且为“全局匹配”模式,才能替换所有的today
    

    String.prototype.split()

    字符串对象的split方法按照正则规则分割字符串,返回一个由分割后的各个部分组成的数组。该方法接受两个参数,第一个参数是正则表达式,表示分隔规则,第二个参数是返回数组的最大成员数。

    str.split(分隔符,返回数组的最大成员数)
    
    // 非正则分隔
    'a,  b,c, d'.split(',')
    // [ 'a', '  b', 'c', ' d' ]
    
    // 正则分隔,去除多余的空格
    'a,  b,c, d'.split(/, */)
    // [ 'a', 'b', 'c', 'd' ]
    
    // 指定返回数组的最大成员
    'a,  b,c, d'.split(/, */, 2)
    [ 'a', 'b' ]
    

    正则表达式匹配规则

    常用元字符串

    元字符 说明
    \d 匹配数字
    \D 匹配任意非数字的字符
    \w 匹配字母或数字或下划线
    \W 匹配任意不是字母,数字,下划线
    \s 匹配任意的空白符
    \S 匹配任意不是空白符的字符
    . 匹配除换行符以外的任意单个字符
    ^ 表示匹配行首的文本(以谁开始)
    $ 表示匹配行尾的文本(以谁结束)

    限定符

    限定符 说明
    * 重复零次或更多次
    + 重复一次或更多次
    ? 重复零次或一次
    {n} 重复n次
    {n,} 重复n次或更多次
    {n,m} 重复n到m次

    其他

    1. [] 字符串用中括号括起来,表示匹配其中的任一字符,相当于或的意思
    2. [^] 匹配除中括号以内的内容
    3. \ 转义符
    4. | 或者,选择两者中的一个。注意|将左右两边分为两部分,而不管左右两边有多长多乱
    5. () 从两个直接量中选择一个,分组

    正则表达式贪婪匹配

    默认情况下都是最大可能匹配,即匹配到下一个字符不满足匹配规则为止。这被称为贪婪模式。

    var s = 'aaa';
    s.match(/a+/) // ["aaa"]
    

    上面代码中,模式是/a+/,表示匹配1个a或多个a,那么到底会匹配几个a呢?因为默认是贪婪模式,会一直匹配到字符a不出现为止,所以匹配结果是3个a。

    除了贪婪模式,还有非贪婪模式,即最小可能匹配。只要一发现匹配,就返回结果,不要往下检查。如果想将贪婪模式改为非贪婪模式,可以在量词符后面加一个问号。

    var s = 'aaa';
    s.match(/a+?/) // ["a"]
    

    上面例子中,模式结尾添加了一个问号/a+?/,这时就改为非贪婪模式,一旦条件满足,就不再往下匹配,+?表示只要发现一个a,就不再往下匹配了。

    除了非贪婪模式的加号(+?),还有非贪婪模式的星号(*?)和非贪婪模式的问号(??)。

    1. +?:表示某个模式出现1次或多2 次,匹配时采用非贪婪模式。
    2. *?:表示某个模式出现0次或多次,匹配时采用非贪婪模式。
    3. ??:表格某个模式出现0次或1次,匹配时采用非贪婪模式。

    组匹配

    正则表达式的括号表示分组匹配,括号中的模式可以用来匹配分组的内容。

    /fred+/.test('fredd') // true
    /(fred)+/.test('fredfred') // true
    

    分组捕获

    var m = 'abcabc'.match(/(.)b(.)/);
    m
    // ['abc', 'a', 'c']
    

    上面代码中,正则表达式/(.)b(.)/一共使用两个括号,第一个括号捕获a,第二个括号捕获c。注意,使用组匹配时,不宜同时使用g修饰符,否则match方法不会捕获分组的内容。
    括号还可以嵌套

    /y((..)\2)\1/.test('yabababab') // true
    

    上面代码中,\1指向外层括号,\2指向内层括号。

    非捕获组

    (?:x)称为非捕获组(Non-capturing group),表示不返回该组匹配的内容,即匹配的结果中不计入这个括号。

    非捕获组的作用请考虑这样一个场景,假定需要匹配foo或者foofoo,正则表达式就应该写成/(foo){1, 2}/,但是这样会占用一个组匹配。这时,就可以使用非捕获组,将正则表达式改为/(?:foo){1, 2}/,它的作用与前一个正则是一样的,但是不会单独输出括号内部的内容。

    var m = 'abc'.match(/(?:.)b(.)/);
    m // ["abc", "c"]
    

    先行断言和先行否定断言

    1. x(?=y)称为先行断言(Positive look-ahead),x只有在y前面才匹配,y不会被计入返回结果。比如,要匹配后面跟着百分号的数字,可以写成/\d+(?=%)/。

    2. x(?!y)称为先行否定断言(Negative look-ahead),x只有不在y前面才匹配,y不会被计入返回结果。比如,要匹配后面跟的不是百分号的数字,就要写成/\d+(?!%)/。

    相关文章

      网友评论

          本文标题:正则表达式

          本文链接:https://www.haomeiwen.com/subject/evqujktx.html