最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 进阶的正则表达式

    正文概述 掘金(SDYZ)   2021-01-21   499

    青铜-正则基础

    正则表达式是用于匹配字符串中字符组合的模式。

    创建正则表达式

    • 使用正则表达式字面量创建 /ab+c/g
    • 调用 RegExp 对象的构造函数创建 new RegExp("ab+c","g")
      • 接收两个参数,第一个参数是字符串或正则表达式,第二个参数是修饰符(flag)
      • 如果第一个参数是正则表达式,那么只使用会使用第二个参数的修饰符,而忽略原有正则表达式的修饰符(ES6 扩展)

    RegExp 对象

    1. 实例属性和方法

    • RegExp.prototype.exec(str)
    • RegExp.prototype.test(str)
    • RegExp.prototype.flags (ES6) 返回正则表达式的修饰符
    • RegExp.prototype.sticky (ES6) 表示是否设置了 y 修饰符 ...

    2. 静态属性

    • RegExp.lastIndex

    3. 字符串对象

    有 6 个方法可以使用正则表达式

    • str.search(regexp)

    • str.match(regexp) 返回一个数组

    • str.replace(regexp|substr, newSubStr|function)

    • str.split(separator) 分隔符 separator 包括 str|regexp

    • str.matchAll() - ES2020 新增

    • str.replaceAll() - ES2020 新增

    4. RegExp.prototype.test(str) 和 String.prototype.search(regexp)

    • test() 判断正则表达式与指定的字符串是否匹配,返回 true 或 false。
    • 类似于 String 的 search() 方法,返回匹配的索引,否则返回-1
    let str = "hello world!";
    /world/.test(str); //  true
    
    let str = "hello world!";
    str.search(/world/); //  6
    

    若想知道更多返回信息(然而执行比较慢),可使用 exec() 方法 ⬇️ ⬇️ ⬇️

    5. RegExp.prototype.exec(str) 和 String.prototype.match(regexp)

    • exec() 在指定字符串中搜索匹配。匹配成功返回一个数组,并更新正则表达式对象的 lastIndex 属性
      • 数组包括:第一项是匹配成功的文本、第二项起是相关的捕获组内容、以及其他属性(index 匹配到的索引值 、input 原始字符串、groups 命名捕获组)
    • match() 也是返回一个数组,包括第一个完整匹配,及其相关的捕获组(返回结果与 exec() 方法相同)
    • 当 match() 方法使用 g 标志,会返回匹配的所有结果
    // 返回结果相同
    let str = "hello world world!";
    /world/.exec(str);
    
    let str = "hello world world!";
    str.match(/world/);
    
    // 会返回匹配的所有结果
    let str = "hello world world!";
    str.match(/world/g);
    

    编写一个正则表达式

    正则表达式由简单字符 + 特殊字符组成

    1. 6 个可选标识 (flags)

    正则表达式有六个可选参数 (flags) 允许全局和不分大小写搜索等

    • g 全局搜索 global
    • i 不区分大小写搜索 ignorecase
    • m 多行搜索 multiline
    • s 允许 . 匹配换行符 (ES2018)
    • u unicode 模式匹配 (ES6)
    • y 执行“粘性(sticky)”搜索,匹配从目标字符串的当前位置开始 (ES6)

    语法:

    • let regExp = /pattern/flags;
    • let regExp = new RegExp("pattern", "flags");
    let str = "Hello World!";
    /world/i.test(str); //  true
    

    2. 特殊字符

    在正则表达式中具有特殊意义的专用字符,可以分为: 特殊字符、量词、范围/组、断言、Unicode 属性转义。

    1. 特殊单字符

    • . 匹配任意字符(除换行符外)
    • \d 匹配数字 digit => [0-9]
    • \D 匹配非数字 => [^0-9]
    • \w 匹配一个字符 word(包括字母数字下划线) => [A-Za-z0-9_]
    • \W 匹配非字符 => [^a-za-z0-9_]
    • \s 匹配空白字符 space,包括空格、制表符、换页符和换行符
    • \S 匹配非空白字符
    • \b 匹配一个单词的边界 boundary
    • \r 匹配回车符
    • \n 匹配换行符
    • \uhhhh 匹配十六进制数表示的 Unicode 字符
    • \u{hhhh} 匹配十六进制数表示的 Unicode 字符(ES6 新增写法,需要设置 u 标志)
    let str = "He played the King in a8 and she moved her Queen in c2.";
    str.match(/\w\d/g); // ["a8","c2"]
    
    // 匹配 Unicode 字符
    let str = "happy ?, confused ?, sad ?";
    let reg = /[\u{1F600}-\u{1F64F}]/gu;
    str.match(reg); // ['?', '?', '?']
    
    // 匹配中文字符 [\u4e00-\u9fa5]
    let str = "123我是456中文";
    let reg = /[\u4e00-\u9fa5]/g;
    str.match(reg); // ["我", "是", "中", "文"]
    

    2. 量词

    • * 匹配 0 次以上(0+ 即有没有都行) => {0,}

    • + 匹配 1 次以上 (1+ 即至少一次)=> {1,}

    • ? 匹配 0 或 1 次(可选,可能有可能没有,有点像 TS 的可选)=> {0,1}

    • {n} 匹配字符刚好出现 n 次

    • {n,m} 至少 n 次,最多 m 次

    • {n,} 至少出现了 n 次

    // 匹配规则:一个或多个字符 和 一个空格,全局匹配,忽略大小写
    let re = /\w+\s/gi;
    "fee fi fo fum".match(re); // ["fee ", "fi ", "fo "]
    

    3. 范围 Range / 组 group

    • [xyz] 字符集合,匹配方括号中的任意字符, 破折号(-)可以指定范围
    • [^xyz] 反向字符集,匹配任何没有包含在方括号中的字符
    • x|y 匹配 x 或 y
    let str = "The Caterpillar and Alice looked at each other";
    let reg = /\b[a-df-z]+\b/gi;
    str.match(reg);  // ["and", "at"]
    
    • (x) 1. 分组 2. 捕获,匹配 x 并记住匹配项,后续通过 \n 来引用第 n 个捕获的组,替换时使用 $n 来指代。
    • (?:x) 非捕获括号,匹配的子字符串不会被记住,可以节省性能
    let reg = /(apple) (banana) \1 \2/;
    "apple banana apple banana apple banana".match(reg);
    
    let reg = /(\w+)\s(\w+)/;
    let str = "John Smith";
    str.replace(reg, "$2 $1"); // "Smith, John"
    

    4. 断言-主要是对边界的判断

    • ^ 匹配输入的开始(注意:字符集合[^xyz]中表示反向)

    • $ 匹配输入的结束

    • \b 匹配一个单词的边界

    • x(?=y) 先行断言,匹配 x (仅当后面为 y) 如: /Jack(?=Sparrow)/ 匹配 Jack

    • (?<=y)x 后行断言(ES2018),匹配 x (仅当前面为 y) /(?<=Jack)Sparrow/ 匹配 Sparrow

    let str = "https://xxx.xx.com/#/index?type=xx&value=xxx";
    let reg = /(?<=\?).+/g;
    str.match(reg); // ['type=xx&value=xxx']
    
    // 条件过滤
    let oranges = ["ripe orange A", "green orange B", "ripe orange C"];
    oranges.filter((item) => item.match(/(?<=ripe )orange/)); //  ["ripe orange A", "ripe orange C"]
    
    • x(?!y) 先行否定断言,匹配 x (仅当后面不为 y) /Jack(?!Sparrow)/
    • (?<!y)x 后行否定断言(ES2018),匹配 x (仅当前面不为 y) /(?<!Jack)Sparrow/

    白银-正则进阶

    下面主要是一些(ES6 新增)修饰符与对应的属性

    g 修饰符 与 lastIndex 属性

    • lastIndex 用来指定“下一次匹配的起始索引”,需要设置 g 标志才生效
    • 因为在设置了 g 标志位的情况下,RegExp 对象是有状态的,会将上次成功匹配后的位置记录在 lastIndex 属性中
    • 使用 exec() / test() 方法匹配成功后,会更新正则对象的 lastIndex 属性,匹配失败 lastIndex 重置为 0
    let regExp = /ab*/g;
    regExp.exec("abbcdefabh"); // ['abb',index:0]
    regExp.lastIndex; // 3
    // 继续匹配
    regExp.exec("abbcdefabh"); // ['ab',index:7]
    regExp.lastIndex; // 9
    // 再继续匹配
    regExp.exec("abbcdefabh"); // null
    regExp.lastIndex; // 0
    

    有了上述特性,exec() / test () 方法可对字符串进行循环匹配(查找出所有匹配)

    let reg = /ab*/g;
    let str = "abbcdefabh";
    let arr = [];
    while ((arr = reg.exec(str)) !== null) {
      console.log(arr, reg.lastIndex);
    }
    // 对比 match ,只会返回匹配到的结果
    str.match(reg); // ['abb','ab']
    

    y 修饰符 与 sticky 属性(ES6)

    • y 也叫做“粘连”修饰符,也是全局匹配
    • 与 g 修饰符区别是,g 修饰符只要剩余位置中存在匹配就可,而 y 修饰符确保“匹配必须从剩余的第一个位置开始”,即粘连。
    let regExp = /ab*/y;
    regExp.exec("abbcdefabh"); // ['abb',index:0]
    regExp.lastIndex; // 3
    // 继续匹配
    regExp.exec("abbcdefabh"); //null
    regExp.lastIndex; // 0
    
    regExp.sticky; // true 表示设置了y修饰符
    

    理解: y 修饰符号隐含了头部匹配的标志。y 修饰符的设计本意,就是让头部匹配的标志^在全局匹配中都有效。

    u 修饰符 与 unicode 属性(ES6)

    • u 修饰符用来匹配大于 \uFFFF 的 Unicode 字符 (ES6)(\uhhhh 匹配十六进制数表示的 Unicode 字符)
    • unicode 属性,表示是否设置了 u 修饰符
    
    /^\uD83D/.test('\uD83D\uDC2A') // true "\uD83D\uDC2A"代表一个字符
    /^\uD83D/u.test('\uD83D\uDC2A') // false
    
    let  r = /hello/u;
    r.unicode; // true
    

    s 修饰符 与 dotAll 属性(ES6)

    • ES5 中 . 匹配任意字符(除换行符外)
    • ES2018 新增 s 修饰符,使得 . 可以匹配任意单个字符,称为 dotAll 模式。
    /foo.bar/.test("foo\nbar"); // false
    // ES2018
    /foo.bar/s.test("foo\nbar"); // true
    /foo.bar/s.dotAll; // true
    

    黄金-正则深入

    具名组匹配

    1. 组匹配

    // exec() 返回数组的第一项是匹配成功的文本,从第二项起,每项都对应“捕获括号”里匹配成功的文本
    let regex = /(\d{4})-(\d{2})-(\d{2})/;
    regex.exec("1999-12-31"); // ["1999-12-31", "1999", "12", "31", index: 0,groups: undefined]
    

    每一组的匹配含义不容易看出来,而且只能用数字序号引用 \n

    2. 具名组匹配 (ES2018)

    允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用。

    语法: /?<组名字>(x)/

    let regex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
    regex.exec("1999-12-31");
    // ["1999-12-31", "1999", "12", "31", index: 0,groups: {day: "31",month: "12",year: "1999"}]
    

    3. 解构赋值

    将匹配结果返回的数组直接解构

    let {
      groups: { one, two },
    } = /^(?<one>.*):(?<two>.*)$/u.exec("foo:bar");
    one; // foo
    two; // bar
    

    4. 替换

    替换时,用 %<组名字> 引用具名组

    let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
    
    "2015-01-02".replace(re, "$<day>/$<month>/$<year>");
    // '02/01/2015'
    

    字符串(新增)方法

    String.prototype.matchAll(regexp) (ES2020)

    • matchAll() 方法可以一次性取出所有匹配,且包含捕获组。返回的是一个遍历器(Iterator)
    • 正则表达式必须设置全局模式 g ,否则会抛出异常 TypeError

    在 matchAll 出现之前,通过在循环中调用 regexp.exec() 来获取所有匹配项信息 如果使用 matchAll ,就可以不必使用 while 循环加 exec 方式了

    let regexp = /t(e)(st(\d?))/g;
    let str = "test1test2";
    
    // match 方式匹配
    str.match(regexp); // ['test1', 'test2']
    
    // exec 方式匹配
    regexp.exec(str); //  ["test1", "e", "st1", "1", index: 0 ]
    
    // matchAll 方式匹配,可以更好地获取捕获组
    [...str.matchAll(regexp)]; // [Array(4), Array(4)]
    

    String.prototype.replace(regexp|substr, newSubStr|function)

    当第一个参数为正则表达式,第二个参数为函数时:

    • str.replace(regexp, function)
    • function 参数如下,也是返回一个新字符串,来替换 regexp 匹配到的结果
    let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
    "2015-01-02".replace(
      re,
      (
        matched, // 匹配结果
        capture1, // 匹配组1(必须对应上)
        capture2, // 匹配组2
        capture3, // 匹配组3
        index, // index
        input, // input
        groups // 具名组
      ) => {
        console.log(matched, capture1, capture2, capture3, index, input, groups);
        let { day, month, year } = groups;
        return `${day}/${month}/${year}`;
      }
    ); // "02/01/2015"
    

    String.prototype.replaceAll(regexp|substr, newSubstr|function) (ES2021)

    • 可以一次性替换所有匹配
    • 当第一个参数为正则表达式(必须带 g 修饰符),第二个参数为函数时 function 参数 与 replace 用法相同

    参考

    正则表达式

    regexper

    c.runoob.com/front-end/8…

    阮一峰-正则的扩展

    Unicode 编码在线转换

    Unicode 与 JavaScript 详解


    起源地下载网 » 进阶的正则表达式

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元