美文网首页
JavaScript正则表达式(元字符|字符类|范围类|预定义类

JavaScript正则表达式(元字符|字符类|范围类|预定义类

作者: Fighting_001 | 来源:发表于2018-12-31 21:43 被阅读63次

    目录结构

    一、正则表达式-概念
    二、正则表达式实践操作
    1. REGEXP对象
        1)字面量
        2)构造函数
    2. 元字符
    3. 字符类
    4. 范围类
    5. JS预定义类&边界
        1)预定义类
        2)边界
    6. 量词
    7. JS正则贪婪模式 & 非贪婪模式
        1)贪婪模式
        2)非贪婪模式
    8. 分组
    9. 前瞻
    10. JS对象属性
    11. JS的test()方法、exec()方法
        1)RegExp.prototype.test(str)
        2)RegExp.prototype.exec(str)
    12. JS字符串对象方法
        1)String.prototype.search(reg)
        2)String.prototype.match(reg)
        3)String.prototype.split(reg)
        4)String.prototype.replace()
    

    一、正则表达式-概念

    正则表达式:Regular Expression。使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。通俗而言,按照某种规则去匹配符合条件的字符串,正则表达式即匹配字符串所采用的规则。

    通过正则表达式,可在IDE中处理规则复杂的字符串查找、替换需求,在JavaScript程序设计中使用正则表达式高效率处理字符串。

    语法:
    /正则表达式主体/修饰符(可选)
    正则表达式主体:用于检索要匹配的字符
    修饰符:用于对检索规则的约束or扩展

    二、正则表达式实践操作

    1. REGEXP对象

    RegExp对象:在 JavaScript 中,RegExp 对象是一个预定义了属性和方法的正则表达式对象

    JavaScript通过内置对象RegExp,支持正则表达式进行实例化RegExp对象(创建对象)有2种方法:字面量;构造函数

    1)字面量

    字面量:指特定的数字、字符串or布尔值,能够明确表现自己的类型并为变量进行赋值的值

    示例:

    let aNumber = 3         //整型字面量
    let aString = "Hello"   //字符串字面量
    let aBool = true        //布尔值字面量
    

    RE.js

    //定义正则表达式
    var reg1 = /\bgood\b/;
    var reg2 = /\bgood\b/g;
    //定义字符串
    var str = "good good study, day day up";
    //使用replace()函数对字符串替换操作
    var r1 = str.replace(reg1, "GOOD");
    var r2 = str.replace(reg2, "GOOD");
    var r3 = str.replace("day", "Day");
    //输出替换结果
    console.log(r1 + "\n" + r2 + "\n" + r3);
    

    运行结果:

    也可在浏览器的Console控制台界面对JavaScript进行操作,如下:

    2)构造函数
    var reg = new RegExp('\\bgood\\b', 'g');
    var str = "good good study, day day up";
    var r = str.replace(reg, "GOOD");
    console.log(r);
    

    以上,\b包含特殊字符,需要转义,写成\\b

    修饰符
    符号 含义
    g global,表示全文搜索;若不添加g,则搜索到第一个匹配结果即停止匹配
    i ignore case,忽略大小写;若不添加i,则默认大小写严格匹配
    m multiple lines,多行搜索

    2. 元字符

    正则表达式由2种基本字符类型组成:

    • 1)原义文本字符:表示原来字符含义的字符。
      如:abc、123
    • 2)元字符:指有特殊含义的非字母字符。
      包括:*?$^.|\(){}[]
      如:\b 匹配边界,\n 换行,\d 数字,\s 空白字符

    3. 字符类

    一般情况下,正则表达式的一个字符匹配一个字符。如:abc 匹配 "abc"。对于正则匹配多个字符的场景,可使用元字符 [] 来构建一个简单的类(泛指符合某些特性的对象,非特指某个字符)。

    案例1:

    表达式 [abc] 把字符a、b、c归为一类,表达式可以匹配该类的任一字符(a或b或c)
    实现效果:字符a、b、c都被替换成设置的A

    案例2:

    字符类取反(反向类/负向类)
    元字符:^
    含义:不属于某个类的内容
    表达式:[^abc] 表示非字符(a或b或c)的内容
    实现效果:匹配到a/b/c字符以外的其他字符并替换成A

    4. 范围类

    若以上使用字符类正则 [0123456789] 匹配数字,以及所有英文字母的匹配,写起来相对比较麻烦且效率不高。为了改善此种场景下字符类的正则写法,正则表达式提供了范围类,如:可使用 [a-z] 来匹配从a到z的任意字符(包含a和z)。

    案例1:
    var r = 'a1b2c3x6z9ABc'.replace(/[a-z]/g, 'Q');
    console.log(r);
    

    运行结果:
    将所有的小写字母都替换成了Q

    案例2:

    [] 组成的类内部可以连写,如:[a-zA-z0-9] 匹配所有的大小写字母、数字字符

    var r = 'a1b2c3x6z9ABc'.replace(/[a-zA-Z0-9]/g, 'Q');
    console.log(r);
    
    案例3:

    在范围类之内匹配包含有连接符 - ,正则如:[0-9-]
    使用范围类,在[]内字符范围之后新增连接符:

    var r = '2018-12-22'.replace(/[0-9-]/g, 'Q');
    console.log(r);
    

    对比组1:使用范围类,匹配数字字符

    var r = '2018-12-22'.replace(/[0-9]/g, 'Q');
    

    对比组2:不使用范围类,直接用连接符作为正则字体

    var r = '2018-12-22'.replace(/-/g, 'Q');
    

    5. JS预定义类&边界

    1)预定义类

    正则表达式提供预定义类来匹配常见的字符类,常用的预定义类:.\d\D\s\S\w\W

    字符 等价类 含义
    . [^\r\n] 除了回车、换行符之外的其他字符
    \d [0-9] 数字字符
    \D [^0-9] 非数字字符
    \s [\t\n\x0B\f\r] 空白符
    \S [^\t\n\x0B\f\r] 非空白符
    \w [a-zA-Z_0-9] 单词字符(字母、数字、下划线)
    \W [^a-zA-Z_0-9] 非单词字符

    结合英文原义记忆:
    d ==> digit(数字)
    s ==> space(空白)
    w ==> word(单词)

    案例:

    匹配字符串:abc+数字+任意字符
    正则写法1:abc[0-9][^\r\n]
    正则写法2:abc\d.

    2)边界

    常用的边界匹配字符:^$\b\B

    字符 含义
    ^ 以xxx开始
    $ 以xxx结束
    \b 单词边界
    \B 非单词边界

    b ==> boundary(边界)

    案例1:元字符 \b\B 的使用

    对比组1:匹配字符"is",其左右皆无边界

    var str = 'This is JavaScript';
    var r = str.replace(/is/g, 'A');
    console.log(r);
    

    对比组2:匹配单词is,其左右皆有边界

    var r = str.replace(/\bis\b/g, 'A');
    

    对比组3:匹配字符"is",其左边无单词边界,右边有单词边

    var r = str.replace(/\Bis\b/g, 'A');
    
    案例2:元字符 ^$ 的使用

    对比组1:

    var str = '@999@777@';
    var r = str.replace(/@./g, 'A');
    console.log(r);
    

    对比组2:

    var r = str.replace(/^@./g, 'A');
    

    对比组3:

    var r = str.replace(/.@/g, 'A');
    

    对比组4:

    var r = str.replace(/.@$/g, 'A');
    
    案例3:多行匹配(修饰符:m

    对比组1:

    var str = 
    "@123\n@456\n@789";
    var r = str.replace(/^@\d/g, 'A');
    console.log(r);
    

    对比组2:

    var r = str.replace(/^@\d/gm, 'A');
    

    6. 量词

    匹配一个出现n次的字符串,n=0,1,...,N

    字符 含义
    ? 0或1 次
    + ≥1 次
    * ≥0 次(任意次)
    {n} n 次
    {n,m} n到m 次
    {n,} ≥n 次

    7. JS正则贪婪模式 & 非贪婪模式

    1)贪婪模式:

    尽可能多的匹配(首先取最多可匹配的数量为一组进行匹配),当匹配剩余的字符串,还会继续尝试新的匹配,直到匹配不到为止,为默认模式

    案例:对字符串"123456789",匹配其中的数字3-6次:\d{3,6},并替换为特定字符
    ==> 先匹配数字出现6次的字符串(123456),然后再从剩余字符串(789)中匹配出现数字3次的情况,剩余字符若没有出现数字3次则停止匹配

    var str = "12345678";
    var r = str.replace(/\d{3,6}/g, 'A');
    console.log(r);
    
    var str = "123456789";
    
    2)非贪婪模式:

    尽可能少的匹配(每次取最少匹配的数量为一组进行匹配),直到匹配不到为止
    使用方法:在量词后加上 ?

    var str = "0123456789";
    var r = str.replace(/\d{3,6}?/g, 'A');
    console.log(r);
    

    以上,是对 012、345、678分组匹配,剩余字符9未能再匹配

    8. 分组

    使用 () 进行分组,使量词作用于分组内的整体部分。如:(Candy){3}

    var str = "a1b2c3d456789";
    var r = str.replace(/([a-z]\d){3}/g, 'A');
    console.log(r);
    

    :使用符号 |
    可联合分组符号使用,如下:

    var str = "Nancy-Lucy";
    var r = str.replace(/(Nan|Lu)cy/g, 'A');
    console.log(r);
    

    反向引用:使用符号 $,作为变量,捕获并引用分组内的内容

    var str = "2018-12-31";
    var r = str.replace(/(\d{4})-(\d{2})-(\d{2})/g, '$3/$2/$1');
    console.log(r);
    

    忽略分组:既想使用分组,又不希望捕获分组,则只需要在分组内的左侧加上符号 ?:

    var str = "Date: 2018-12-31";
    var r = str.replace(/(?:.*)(\d{4})-(\d{2})-(\d{2})/g, '$3/$2/$1');
    console.log(r);
    

    9. 前瞻

    :正则表达式从文本头部向尾部开始解析,文本尾部方向即为“前”;预示“未来的”方向,待匹配的方向
    前瞻:在正则匹配到规则时,向前检查是否符合断言;后顾/后瞻方向相反(JavaScript不支持后顾)
    正向/肯定 匹配:符合特定断言
    负向/否定 匹配:不符合特定断言
    断言:JavaScript前瞻的语法

    既要符合exp正则,又要满足断言要求

    名称 正则写法 含义
    正向前瞻 exp(?=assert) 符合exp正则,且符合设置的断言
    负向前瞻 exp(?!assert) 符合exp正则,且不符合设置的断言

    PS:以上断言部分只作为约束条件而存在,并不会参与字符本身的匹配和替换,匹配字符的是exp正则部分

    案例:

    约束条件:\w(?=\d),单词字符后需要紧跟着数字
    匹配:\w,单词字符(字母、数字、下划线)

    var str = "abc1-23_45";
    var r = str.replace(/\w(?=\d)/g, 'A');
    console.log(r);
    

    以上,c1、23、_4、45都满足约束条件,则分别将会把每组符合条件的字符串中左边的单词字符替换为"A",即:A1、A3、AA5

    10. JS对象属性

    对象属性:

    名称 含义
    global g:全文搜索,默认false
    ignoreCase i:大小写敏感,默认false
    multiline m:多行搜索,默认false
    lastIndex 下次匹配的起始位置
    该属性只有设置标志g才能使用,实现遍历检索匹配
    source 正则的文本字符串(正则主体)

    语法:

    RegExpObject.global
    RegExpObject.ignoreCase
    RegExpObject.multiline
    RegExpObject.lastIndex
    RegExpObject.source
    

    11. JS的test()方法、exec()方法

    1)RegExp.prototype.test(str)

    作用:测试字符串参数中是否存在所匹配正则的字符串。若存在则返回true,否则返回false

    prototype:JavaScript中的每个函数作为一个对象,每个函数对象都拥有一个子对象prototype。prototype是全局属性,适用于所有的Javascript对象,允许向对象添加属性和方法
    RegExp.exec() 和 RegExp.test()方法都以 lastIndex 属性所指的位置作为下次检索的起始点,可通过反复调用这2个方法来遍历一个字符串中的所有匹配文本。当这2个方法再也找不到可以匹配的文本时,它们会自动把 lastIndex 属性重置为 0。

    正则中无 g 标志:

    正则中有 g 标志:

    对于设置的参数,当有效匹配其中字符串时,获取对应lastIndex的取值:

    以上,根据lastIndex属性指定的下一次检索起始点,正则反复调用test()方法匹配文本过程中,当匹配到文本时返回true,遍历直到未匹配到文本时返回false,然后此时test()方法将lastIndex属性重置为0;再次匹配时又会重新开始循环,因此同一个参数的同一正则连续匹配时会出现周期循环返回true和false的结果。

    2)RegExp.prototype.exec(str)

    使用正则对字符串执行搜索,并更新全局RegExp对象的属性,即根据lastIndex属性反映匹配结果。若字符串中有匹配的值返回该匹配值(以数组形式展示),否则返回 null

    所返回结果数组的属性:
    index:声明匹配文本的第1个字符的位置
    input:存放被检索的字符串string

    对于非全局调用:
    调用非全局的RegExp对象的exec()方法时,返回的是数组,其中:
    第1个元素:与正则匹配的文本
    第2个元素:RegExp对象的第1个子表达式(如:分组)相匹配的文本
    ...
    第n个元素:RegExp对象的第(n-1)个子表达式相匹配的文本

    var reg3 = /\d(\w)(\w)\d/;
    var reg4 = /\d(\w)(\w)\d/g;
    var str = '$1ab2cd3ef4gh5ijk'
    var result = reg3.exec(str);
    
    var r3 = reg3.lastIndex + '\t' + result.index + '\t' + result.toString();
    console.log(r3);
    
    console.log('----------------');
    
    while (result = reg4.exec(str)) {
        var r4 = reg4.lastIndex + '\t' + result.index + '\t' + result.toString();
        console.log(r4);
    }
    

    12. JS字符串对象方法

    1)String.prototype.search(reg)

    search()方法
    用于检索字符串中指定的子字符串,or检索与正则匹配的子字符串。该方法返回第一个匹配结果的index,检索不到则返回-1;该方法将忽略标志g,不执行全局匹配,且总是从字符串的开始进行检索

    2)String.prototype.match(reg)

    match()方法
    将检索字符串,以找到一个or多个正则匹配的文本;该方法会受到标志g的影响

    非全局调用
    当正则没有标志g时,match()方法只能在字符串中执行1次匹配。
    若没有找到如何匹配的文本,则返回null;否则若匹配到文本,则返回一个数组,在其中存放有找到匹配文本相关的信息。所返回的数组如下:
    ①元素
    第1个元素:存放匹配的文本
    其余元素:存放于正则子表达式匹配的文本

    ②对象属性
    index:声明匹配文本的起始字符在字符串中的位置
    input:声明对String对象的引用

    全局调用
    当正则有标志g时,match()方法将执行全局搜索,找到字符串中所有匹配的子串。若没有找到任何匹配的子串,则返回null;若找到1个or多个匹配的子串,则返回一个数组:数组中存放字符串中所有匹配的子串,但没有index和input属性

    var reg3 = /\d(\w)(\w)\d/;
    var reg4 = /\d(\w)(\w)\d/g;
    var str = '$1ab2cd3ef4gh5ijk'
    var result = str.match(reg3);
    
    console.log(result);
    
    var r3 = reg3.lastIndex + '\t' + result.index + '\t' + result.toString();
    console.log(r3);
    
    console.log('----------------');
    
    var result = str.match(reg4);
    console.log(result);
    var r4 = reg4.lastIndex + '\t' + result.index + '\t' + result.toString();
    console.log(r4);
    

    PS:
    【1】对于非全局调用,exec()方法的参数是字符串,使用:reg.exec(str);match()方法的参数是正则表达式,使用:str.match(reg),此时两个方法的返回结果是一致的结构
    【2】对于全局调用,match()方法比exec()方法匹配的数据较少(如:不会返回匹配的具体字符位置、分组信息,主要给出所匹配的子串),但match(reg)方法匹配效率更高

    3)String.prototype.split(reg)

    split()方法
    将字符串分割为字符数组

    var arr1 = 'a,b,c'.split(',');
    console.log(arr1);
    
    var arr2 = 'a,b,c,d'.split(/,/);
    console.log(arr2);
    
    var arr3 = 'a1b2c3d4e'.split(/\d/);
    console.log(arr3);
    
    var arr4 = 'a1b|c_d2e-f'.split(/[\d|_-]/);
    console.log(arr4);
    
    4)String.prototype.replace()

    replace()方法
    查找字符并替换为新的字符,or替换一个与正则匹配的子串
    使用:

    String.prototype.replace(str, replaceStr)
    String.prototype.replace(reg, replaceStr)
    String.prototype.replace(reg, function)
    

    当替换值为动态值时,可考虑使用 function 函数生成替换文本
    function函数中的参数:
    ①匹配的字符串
    ②正则分组内容(选填)
    ③匹配项在字符串中的index
    ④原字符串

    'a1b2c3d4c5e6'.replace(/\d/g, function(match,index,origin){
        console.log(index);
        return parseInt(match)+1;
    });
    
    '1b23d45c6'.replace(/(\d)(\w)(\d)/g, function(match,group1,group2,group3,index,origin){
        console.log(match);
        return group1+group3;
    });
    

    参考资料:
    [1] JavaScript 正则表达式
    [2] ES5基础之正则表达式02:范围类、预定义类和边界字符

    在线工具:
    [1] Regexper
    [2] JS Bin

    相关文章

      网友评论

          本文标题:JavaScript正则表达式(元字符|字符类|范围类|预定义类

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