zoukankan      html  css  js  c++  java
  • 深入js正则

    开题

    我们常常有正则的各种需求,普通的正则匹配符虽然够用,但是满足不了我们一些很奇怪的需求,所以我们需要更多的关于正则的知识点。

    需求

    比如我们有一个这样的需求,匹配出字符串里的第一个div标签:aa<div>test1</div>bb<div>test2</div>cc

    有这样一个表达式,它的匹配结果是:

    `aa<div>test1</div>bb<div>test2</div>cc `.match(/<div>.*</div>/)  //<div>test1</div>bb<div>test2</div>
    

    还有这样一个表达式,它的匹配:

    `aa<div>test1</div>bb<div>test2</div>cc `.match(/<div>.*?</div>/)  //<div>test1</div>
    

    区别只是第二个匹配多加了个?号。竟有如此操作。

    正则贪婪匹配和非贪婪匹配

    概念

    贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。非贪婪模式只被部分NFA引擎所支持。

    例如

    除了第一个例子,我们再举个例子。最简单的比如

    `aaaaaa`.match(/w+/)  //aaaaaa
    `aaaaaa`.match(/w+?/)  //a
    

    非贪婪模式的语法

    js的正则引擎包括现在大部分的高级语言的正则引擎都是NFA,默认贪婪匹配的,js的匹配符都是贪婪匹配的匹配符也叫匹配优先量词,比如“{m,n}”、“{m,}”、“?”、“*”和“+”。

    非贪婪模式的匹配符也叫忽略优先量词,比如“{m,n}?”、“{m,}?”、“??”、“*?”和“+?”。 就是在贪婪量词后面加?号

    非贪婪模式的应用

    并没有特殊的应用范围,因为正则是需要各种匹配符配合的。

    贪婪模式和贪婪模式的性能

    非贪婪模式的性能要高一点的,是因为贪婪模式可能会遇到更多的回溯。

    NFA的回溯

    谈到回溯,其实就是正则的匹配原理了。例子说话:

    `love`.match(/l(ovv|asd|ove)/)  //love
    

    那么js是如何对这段正则进行匹配的呢

    • 首先控制权交给l,匹配l,成功。
    • 匹配第一个分支,ovv,o匹配成功,继续匹配v匹配成功,e匹配失败,这时回溯,返回第一次成功的匹配l,并且废弃掉此分支。
    • 匹配第二个分支,a,匹配失败,回溯,废弃掉此分支。
    • 匹配第三分支ove,连续匹配都能成功,返回love。

    回溯的原理:

    记录所有可能的表达式分支,尝试匹配,若失败则返回,选择上次正确标记处按新的表达式(备用状态)开始新的尝试匹配。

    回溯就是当正则匹配失败退回成功的匹配。因为js默认是贪婪匹配的,所以如果我们匹配这样一个字符串aaaaaaaaab,表达式为/a+c/。流程是怎样的呢?

    因为贪婪,我们会先匹配全部的a,然后匹配c字符串,匹配失败,这是回溯,吐出一个a来,再匹配c,仍然失败,会再吐出一个a再匹配c,如此往复的回溯,直到剩下最后一个a,再匹配c失败,我们宣布匹配失败。这时已经做了n多次的回溯。所以刚才说贪婪匹配的性能可能是更低的,但也不是绝对的,要取决于你的正则是如何书写的。好的正则需要更少的回溯,会有更好的性能。

    正则的捕获和非捕获

    捕获和非捕获和下面要讲的环视都是NFA引擎区别与DFA引擎的重要部分。捕获的表达式很简单,就是(exp),非捕获的表达式是(?:exp)。捕获的作用就是会捕获括号里的内容,把它放到RegExp.$1 -$9 之中,非捕获的话就是我匹配这个表达式,但是我不把它放到返回中。

    比如:

    `email:xiaoming@toutiao.com`.match(/:(w+)@/)  //[":xiaoming@", "xiaoming", index: 5, input: "email:xiaoming@toutiao.com"]
    

    match函数的第一个返回是全文的匹配,第二个返回是RegExp.$n,即捕获的匹配,我们这样写就很容易获取到xiaoming这个用户名,如果我们写为

    `email:xiaoming@toutiao.com`.match(/:(?:w+)@/)  //[":xiaoming@", index: 5, input: "email:xiaoming@toutiao.com"]
    

    是非捕获但匹配,就是相当于/:w+@/。它有什么用呢?可以把一个东西作为一个整体,比如你可以写/w{2}/你不能写/w{2}+/,你可以写做/(?:w{2})+/。

    正则表达式的环视

    最后说一下正则最难的环视。也有文章叫预搜索。

    • 环视只进行子表达式的匹配,不占有字符,匹配到的内容不保存到最终的匹配结果,是零宽度的。环视匹配的最终结果就是一个位置。
    • 环视的作用相当于对所在位置加了一个附加条件,只有满足这个条件,环视子表达式才能匹配成功。
    • js只支持顺序环视,包括顺序肯定环视和顺序否定环视。

    顺序肯定环视

    表达式为:(?= exp)。表达式的右侧需要满足exp,才能成功匹配。比如

    var con="coming soon,going gogogo"
    var reg = /[w]+(?=ing)/g;   //["com", "go"]
     console.log(con.match(reg)); 
    

    w+需要满足的条件是(ing),顺序肯定环视的表达式满足,才可以匹配。意思就是相当于匹配后面带ing的单词。

    `a12`.match(/^(?=[a-z])[a-z0-9]+$/)    //a12
    

    这个匹配是如何进行的呢?
    首先^匹配位置0,a字母匹配成功,然后进入顺序肯定环视,它和表达式的匹配是不互斥的,它也匹配的a,a匹配成功,进入表达式,匹配a,匹配1,2都成功,$匹配成功,返回a12。
    ^匹配"",[a-z0-9]匹配”a12“,$匹配“”。

    /(?=.*?d)/.test(`asdasdads`)  //匹配字符必须有数字
    
    `<a class='a'>>>asdasdw我啊啊售出<<<<</a>`.match(/(?:<a.*?>)(.*?)(?=</a>)/)
    // ["<a class='a'>>>asdasdw我啊啊售出<<<<", ">>asdasdw我啊啊售出<<<<", index: 0, input: "<a class='a'>>>asdasdw我啊啊售出<<<<</a>"]
    

    顺序否定环视

    表达式为:(?!exp)。相当于在当前位置左侧附加一个条件。如果满足了exp则顺序否定环视宣布匹配失败,如果不满足exp,顺序否定环视宣布匹配成功,再进行下面的匹配。

    比如

    `1111a112`.match(/^(?![d]+$)/g) //匹配字符不能全是数字
    

    最后一道题

    给金钱数额加千分制的区分,比如1,234,567,890。

    `1234567890`.match(/d{1,3}(?=(d{3})+$)/g)
    

    d首先贪婪匹配123,成功,进入顺序肯定环视,456,789匹配成功,控制权交到$匹配789,匹配失败,回溯

    d匹配12,成功,进入顺序肯定环视,345,678匹配成功,控制权交到$匹配678,匹配失败,回溯

    d匹配1,成功,进入顺序肯定环视,234,567,890,控制权交到$匹配890,匹配成功.

    d贪婪匹配234,成功,进入顺序肯定环视,567,890匹配成功,控制权交到$匹配890,匹配成功

    d贪婪匹配567,成功,进入顺序肯定环视,890匹配成功,控制权交到$匹配890,匹配成功

    d贪婪匹配890,成功,进入顺序肯定环视,匹配空字符串匹配失败,匹配失败。

    d匹配89,d匹配8在顺序肯定环视里都会失败,于是返回。

    文档匹配1,234,567

  • 相关阅读:
    【BZOJ-4289】Tax 最短路 + 技巧建图
    【BZOJ-3895】取石子 记忆化搜索 + 博弈
    【BZOJ-4569】萌萌哒 ST表 + 并查集
    【BZOJ-3832】Rally 拓扑序 + 线段树 (神思路题!)
    【BZOJ-4213】贪吃蛇 有上下界的费用流
    【BZOJ-3122】随机数生成器 BSGS
    【BZOJ-2299】向量 裴蜀定理 + 最大公约数
    【BZOJ-1441】Min 裴蜀定理 + 最大公约数
    【BZOJ-2438】杀人游戏 Tarjan + 缩点 + 概率
    【BZOJ-4310】跳蚤 后缀数组 + ST表 + 二分
  • 原文地址:https://www.cnblogs.com/dh-dh/p/7122661.html
Copyright © 2011-2022 走看看