• 【重温基础】9.正则表达式


    本文是 重温基础 系列文章的第九篇。
    今日感受:时间管理-角色管理法。

    系列目录:

    本章节复习的是JS中的正则表达式,JS中用来匹配字符串的强大工具。

    前置知识:
    JS中的正则表达式是用来匹配字符串中指定字符组合的模式。
    另外需要记住:正则表达式也是对象。

    1.创建正则表达式

    • 使用一个正则表达式字面量:
    let reg = /ab+c/;
    let reg = /^[a-zA-z]/gi;
    
    • 使用RegExp对象:
      new RegExp(str[, attr])接收2个参数,str是一个字符串,指定正则表达式匹配规则,attr可选,表示匹配模式,值有g(全局匹配),i(区分大小写的匹配)和m(多行匹配)。
    let reg = new RegExp('ab+c');
    let reg = new RegExp(/^[a-zA-z]/, "gi");
    let reg = new RegExp("^[a-zA-z]", "gi");
    

    正则表达式的返回值,是一个新的RegExp对象,具有指定的模式和标志。
    返回信息介绍

    对象 属性 描述 案例中对应的值
    reg lastIndex 下一个匹配的索引(仅在使用g参数时可用) 0
    reg source 模式文本。在正则表达式创建时更新,不执行。 "ab+c"
    reg ignoreCase 是否使用了 “i” 标记使正则匹配忽略大小写。 true
    reg global 是否使用了 “g” 标记来进行全局的匹配。 true
    reg multiline 是否使用了 “m” 标记使正则工作在多行模式。 false

    关于正则表达式的一些方法属性,文章后面介绍,这里先复习定义和使用

    2.使用正则表达式

    JS的正则表达式可以被用于:

    • RegExp对象的exectest方法;
    • String对象的matchreplacesearchsplit方法。

    2.1 RegExp对象方法

    方法 介绍
    exec 检索字符串中指定的值。返回找到的值,并确定其位置。
    test 检索字符串中指定的值。返回 truefalse

    2.1.1 exec(str)

    str: 需要检索的字符串。
    若检索成功,返回匹配的数组,否则返回null。

    let str = "hello leo!";
    let reg = new RegExp("leo", "g");
    let result = reg.exec(str);
    // 也可以写成
    let result = /leo/g.exec("hello leo!");
    
    /*
    [
        0: "leo",
        groups: undefined,
        index: 6,
        input: "hello leo!",
        length: 1
    ]
    */
    
    let result2 = /(leo S)/g.exec("hello leo hi leo!");
    /*
        0: "leo hi"
        1: "leo hi"
        2: "hi"
        groups: undefined
        index: 6
        input: "hello leo hi leo!"
        length: 3
    */
    

    返回信息介绍

    对象 属性 描述 案例中对应的值
    result [0] 匹配到的所有字符串 "leo"
    result input 初始字符串。 "hello leo!"
    result index 在输入的字符串中匹配到的以0开始的索引值。 6
    result2 [1],...,[n] 括号中的分组捕获 [1]=> "leo hi";[2] => "hi"

    2.1.2 test(str)

    str:需要检索的字符串。
    若匹配成功返回true否则false
    等价于 reg.exec(str) != null

    let str = "hello leo!";
    let res = /^leo/.test(str);   // fasle
    let res1 = /^leo/.test(str);  // true
    

    ^str表示匹配以str开头的字符串,这些符号文章后面会介绍。

    2.2 String对象方法

    方法 介绍
    search 检索与正则表达式相匹配的值。
    match 找到一个或多个正则表达式的匹配。
    replace 替换与正则表达式匹配的子串。
    split 把字符串分割为字符串数组。

    2.2.1 search

    str.search(reg)
    str:被检索的源字符串。
    reg:可以是需要检索的字符串,也可以是需要检索的RegExp对象,可以添加标志,如i

    若检索成功,返回第一个RegExp对象匹配的字符串的起始位置,否则返回-1

    let str = "hello leo!";
    let res = str.search(/leo/g);  // 6
    
    let str1 = "hello leoleoleoleo!";
    let res1 = str.search(/leo/g); // 6
    let res2 = str.search(/pingan/g); // -1
    

    2.2.2 match

    str.match(reg)
    str:被检索的源字符串。
    reg:可以是需要检索的字符串,也可以是需要检索的RegExp对象,可以添加标志,如i

    若检索成功,返回与reg匹配的所有结果的一个数组,数组的第一项是进行匹配完整的字符串,之后的项是用圆括号捕获的结果,否则返回null

    let str = 'For more information, see Chapter 3.4.5.1';
    let reg = /see (chapter d+(.d)*)/i;
    let result = str.match(reg);
    /*
    logs [ 'see Chapter 3.4.5.1',
           'Chapter 3.4.5.1',
           '.1',
           index: 22,
           input: 'For more information, see Chapter 3.4.5.1' ]
    */
    

    'see Chapter 3.4.5.1' 是整个匹配。
    'Chapter 3.4.5.1''(chapter d+(.d)*)'捕获。
    '.1' 是被'(.d)'捕获的最后一个值。
    'index' 属性(22)是整个匹配从零开始的索引。
    'input' 属性是被解析的原始字符串。

    2.2.3 replace

    将字符串中指定字符替换成其他字符,或替换成一个与正则表达式匹配的字符串。
    str.replace(sub/reg,val):

    • str: 源字符串
    • sub: 使用字符串来检索被替换的文本
    • reg: 使用RegExp对象来检索来检索被替换的文本
    • val: 指定替换文本
      返回替换成功之后的字符串,不改变源字符串内容。
    let str = "hello leo!";
    let res = str.replace('leo','pingan');//"hello pingan!"
    

    val可以使用特殊变量名

    变量名 代表的值
    $$ 插入一个 “$”。
    $& 插入匹配的子串。
    $ 插入当前匹配的子串左边的内容。
    $' 插入当前匹配的子串右边的内容。
    $n 假如第一个参数是 RegExp对象,并且 n 是个小于100的非负整数,那么插入第 n 个括号匹配的字符串。提示:索引是从1开始
    let str = "hello leo!";
    let res = str.replace(/(w+)s* s*(w+)/, "$2:$1");
    // "leo:hello!"
    

    2.2.4 split

    将一个字符串,按照指定符号分割成一个字符串数组。
    str.split(sub[, maxlength]):

    • str: 源字符串
    • sub: 指定的分割符号或正则
    • maxlength: 源字符串
    let str = "hello leo!";
    let res = str.split();   //["hello leo!"]
    let res = str.split(""); //["h", "e", "l", "l", "o", " ", "l", "e", "o", "!"]
    let res = str.split(" ");//["hello", "leo!"]
    let res = str.split(/s+/);//["hello", "leo!"]
    
    let res = str.split("",3);//["h", "e", "l"]
    

    2.3 使用情况

    • 当我们想要查找一个字符串中的一个匹配是否找到,可以用testsearch方法。
    • 当我们想要得到匹配的更多信息,我们就需要用到execmatch方法。

    3.正则表达式符号介绍

    详细的每个符号的用法,可以查阅 W3school JavaScript RegExp 对象

    3.1 修饰符

    修饰符 描述
    i 执行对大小写不敏感的匹配。
    g 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
    m 执行多行匹配。
    let str = "hello leo!"
    let res = /Leo/i.test(str); // i 不区分大小写 所以返回true
    let res = /Leo/.test(str);  // fasle
    

    3.2 方括号

    用于查找指定返回之内的字符:

    表达式 描述
    [abc] 查找方括号之间的任何字符。
    [^abc] 查找任何不在方括号之间的字符。
    [0-9] 查找任何从 0 至 9 的数字。
    [a-z] 查找任何从小写 a 到小写 z 的字符。
    [A-Z] 查找任何从大写 A 到大写 Z 的字符。
    [A-z] 查找任何从大写 A 到小写 z 的字符。
    [adgk] 查找给定集合内的任何字符。
    [^adgk] 查找给定集合外的任何字符。
    (red) 查找任何指定的选项。
    let str = "hello leo!";
    let res = str.match(/[a-m]/g);
    //["h", "e", "l", "l", "l", "e"]
    let res = str.match(/[^a-m]/g);
    //["o", " ", "o", "!"]
    

    3.3 元字符

    元字符是拥有特殊含义的字符:

    元字符 描述
    . 查找单个字符,除了换行和行结束符。
    w 查找单词字符。
    W 查找非单词字符。
    d 查找数字。
    D 查找非数字字符。
    s 查找空白字符。
    S 查找非空白字符。
     匹配单词边界。
    B 匹配非单词边界。
    查找 NUL 字符。
    查找换行符。
    f 查找换页符。
    查找回车符。
    查找制表符。
    v 查找垂直制表符。
    xxx 查找以八进制数 xxx 规定的字符。
    xdd 查找以十六进制数 dd 规定的字符。
    uxxxx 查找以十六进制数 xxxx 规定的 Unicode 字符。
    let str = "hello leo hi pingan!";
    let res = str.match(/os/g);
    //["o ", "o "]
    let res = str.match(/s/g);
    //[" ", " ", " "]
    

    3.4 量词

    量词 描述
    n+ 匹配任何包含至少一个 n 的字符串。
    n* 匹配任何包含零个或多个 n 的字符串。
    n? 匹配任何包含零个或一个 n 的字符串。
    n{X} 匹配包含 X 个 n 的序列的字符串。
    n{X,Y} 匹配包含 X 至 Y 个 n 的序列的字符串。
    n{X,} 匹配包含至少 X 个 n 的序列的字符串。
    n$ 匹配任何结尾为 n 的字符串。
    ^n 匹配任何开头为 n 的字符串。
    ?=n 匹配任何其后紧接指定字符串 n 的字符串。
    ?!n 匹配任何其后没有紧接指定字符串 n 的字符串。
    let str = "hello leo!";
    let res = str.match(/^hello/g);
    // ["hello"]
    let res = str.match(/^pingan/g);
    //null
    
    

    4. 正则表达式拓展(ES6)

    4.1 介绍

    在ES5中有两种情况。

    • 参数是字符串,则第二个参数为正则表达式的修饰符。
    let a = new RegExp('abc', 'i');
    // 等价于
    let a = /abx/i;
    
    • 参数是正则表达式,返回一个原表达式的拷贝,且不能有第二个参数,否则报错。
    let a = new RegExp(/abc/i);
    //等价于
    let a = /abx/i;
    
    let a = new RegExp(/abc/, 'i');
    //  Uncaught TypeError
    

    ES6中使用:
    第一个参数是正则对象,第二个是指定修饰符,如果第一个参数已经有修饰符,则会被第二个参数覆盖。

    new RegExp(/abc/ig, 'i');
    

    4.2 字符串的正则方法

    常用的四种方法:match()replace()search()split()

    4.3 u修饰符

    添加u修饰符,是为了处理大于uFFFF的Unicode字符,即正确处理四个字节的UTF-16编码。

    /^uD83D/u.test('uD83DuDC2A'); // false
    /^uD83D/.test('uD83DuDC2A');  // true
    

    由于ES5之前不支持四个字节UTF-16编码,会识别为两个字符,导致第二行输出true,加入u修饰符后ES6就会识别为一个字符,所以输出false

    注意:
    加上u修饰符后,会改变下面正则表达式的行为:

    • (1)点字符
      点字符(.)在正则中表示除了换行符以外的任意单个字符。对于码点大于0xFFFF的Unicode字符,点字符不能识别,必须加上u修饰符。
    var a = "?";
    /^.$/.test(a);  // false
    /^.$/u.test(a); // true
    
    • (2)Unicode字符表示法
      使用ES6新增的大括号表示Unicode字符时,必须在表达式添加u修饰符,才能识别大括号。
    /u{61}/.test('a');      // false
    /u{61}/u.test('a');     // true
    /u{20BB7}/u.test('?'); // true
    
    • (3)量词
      使用u修饰符后,所有量词都会正确识别码点大于0xFFFF的 Unicode 字符。
    /a{2}/.test('aa');    // true
    /a{2}/u.test('aa');   // true
    /?{2}/.test('??');  // false
    /?{2}/u.test('??'); // true
    
    • (4)i修饰符
      不加u修饰符,就无法识别非规范的K字符。
    /[a-z]/i.test('u212A') // false
    /[a-z]/iu.test('u212A') // true
    

    检查是否设置u修饰符:
    使用unicode属性。

    const a = /hello/;
    const b = /hello/u;
    
    a.unicode // false
    b.unicode // true
    

    4.4 y修饰符

    y修饰符与g修饰符类似,也是全局匹配,后一次匹配都是从上一次匹配成功的下一个位置开始。区别在于,g修饰符只要剩余位置中存在匹配即可,而y修饰符是必须从剩余第一个开始。

    var s = 'aaa_aa_a';
    var r1 = /a+/g;
    var r2 = /a+/y;
    
    r1.exec(s) // ["aaa"]
    r2.exec(s) // ["aaa"]
    
    r1.exec(s) // ["aa"]  剩余 '_aa_a'
    r2.exec(s) // null
    

    lastIndex属性:
    指定匹配的开始位置:

    const a = /a/y;
    a.lastIndex = 2;  // 从2号位置开始匹配
    a.exec('wahaha'); // null
    a.lastIndex = 3;  // 从3号位置开始匹配
    let c = a.exec('wahaha');
    c.index;          // 3
    a.lastIndex;      // 4
    

    返回多个匹配
    一个y修饰符对match方法只能返回第一个匹配,与g修饰符搭配能返回所有匹配。

    'a1a2a3'.match(/ad/y);  // ["a1"]
    'a1a2a3'.match(/ad/gy); // ["a1", "a2", "a3"]
    

    检查是否使用y修饰符
    使用sticky属性检查。

    const a = /hellod/y;
    a.sticky;     // true
    

    4.5 flags属性

    flags属性返回所有正则表达式的修饰符。

    /abc/ig.flags;  // 'gi'
    

    5. 正则表达式拓展(ES9)

    在正则表达式中,点(.)可以表示任意单个字符,除了两个:用u修饰符解决四个字节的UTF-16字符,另一个是行终止符。
    终止符即表示一行的结束,如下四个字符属于“行终止符”:

    • U+000A 换行符( )
    • U+000D 回车符( )
    • U+2028 行分隔符(line separator)
    • U+2029 段分隔符(paragraph separator)
    /foo.bar/.test('foo
    bar')
    // false
    

    上面代码中,因为.不匹配 ,所以正则表达式返回false
    换个醒,可以匹配任意单个字符:

    /foo[^]bar/.test('foo
    bar')
    // true
    

    ES9引入s修饰符,使得.可以匹配任意单个字符:

    /foo.bar/s.test('foo
    bar') // true
    

    这被称为dotAll模式,即点(dot)代表一切字符。所以,正则表达式还引入了一个dotAll属性,返回一个布尔值,表示该正则表达式是否处在dotAll模式。

    const re = /foo.bar/s;
    // 另一种写法
    // const re = new RegExp('foo.bar', 's');
    
    re.test('foo
    bar') // true
    re.dotAll // true
    re.flags // 's'
    

    /s修饰符和多行修饰符/m不冲突,两者一起使用的情况下,.匹配所有字符,而^$匹配每一行的行首和行尾。

    参考资料

    1.MDN 正则表达式
    2.W3school JavaScript RegExp 对象


    本部分内容到这结束

    Author 王平安
    E-mail pingan8787@qq.com
    博 客 www.pingan8787.com
    微 信 pingan8787
    每日文章推荐 https://github.com/pingan8787/Leo_Reading/issues
    JS小册 js.pingan8787.com

    bg

    个人博客:http://www.pingan8787.com 微信公众号【前端自习课】和千万网友一起,每日清晨,享受一篇前端优秀文章。 目前已连续推送文章 600+ 天,愿每个人的初心都能一直坚持下去!
  • 相关阅读:
    C#中使用My实现单例应用程序
    喝着啤酒学Python(2):第一个HelloWorld
    再读《精通css》04:盒模型和空白边叠加
    再读《精通css》07:圆角
    再读《精通css》08:阴影
    @ResponseBody 乱码
    再读《精通css》05:定位、浮动与清理
    关于javascript面向对象的一点思考
    再读《精通css》06:背景图片
    【求解释】关于第三方接口调用中安全的疑问
  • 原文地址:https://www.cnblogs.com/pingan8787/p/11838215.html
Copyright © 2020-2023  润新知