写这篇文章的目的一是记录,二是想把自己的领悟整理分享给大家,好让大家了解一下正则表达式到底是如何进行匹配的。这篇文章可能不会很系统的去讲js(毕竟也没那样的能力),就简单分享一下我对正则控制权和传动的理解。话不多说,进入正题。(ps:这篇文章适合有一定js正则基础的人阅读)
1 正则眼中的字符串和位置
在讲控制权和传动之前,了解正则眼中的字符串和位置对理解正则表达式很有用。

上图中一共有8个字符,9个位置,在正则中位置也是可以匹配的,比如^匹配字符串开始位置,$匹配字符串结束位置,它仅仅匹配的是位置,匹配结果中不会出现。同时位置的匹配不是互斥的,即同一个位置可以匹配多次,但字符的匹配是互斥的,只能匹配一次。
2 控制权与传动
了解了正则的位置和字符的概念,理解控制权与传动就容易多了。
控制权是指哪一个正则子表达式(可能为一个普通字符、元字符或元字符序列组成)在匹配字符串,那么控制权就在哪。
传动是指正则引擎的一种机制,传动装置将定位正则从字符串的哪里开始匹配。
正则表达式当开始匹配的时候,一般是由一个子表达式获取控制权,从字符串中的某一个位置开始尝试匹配,一个子表达式开始尝试匹配的位置,是从前一子表达匹配成功的结束位置开始的。
举一个栗子,read(?=ing)ing\sbook匹配reading book,我们把这个正则看成5个子表达式read、(?=ing)、ing、\s、book,当然你也可以吧read看做4个单独字符的子表达式,只是我们这里为了方便这么看待。read从位置0开始匹配到位置4,后面的(?=ing)继续从位置4开始匹配,发现位置4后面确实是ing,于是断言匹配成功,也就是整一个(?=ing)就是匹配了位置4这一个位置而已(这里更能理解什么是零宽了吧),然后后面的ing再从位置4开始匹配到位置7,然后\s再从位置7匹配到位置8,最后的book从位置8匹配到位置12,整一个匹配完成。
3 几个实例
我们再用实际栗子验证一下我们的理解。
栗子1:
‘123456789’.replace(/\B(?=(\d{3})+$)/g,','); // 123,456,789
咋一看到这个表达式属实会有点晕,没关系我们一层层来剥开它的外衣。首先需要知道表达式中的一些元字符代表什么意思。\B 匹配的是非单词边界,就比如abc,从位置0开始匹配,位置0是单词边界,匹配不上,匹配到位置1的时候发现是非单词边界,匹配上了,匹配就结束了,所以匹配的就是位置1。在表达式(\d{3}+$) 中,$匹配结束位置,\d 匹配数字,\d{3}, 匹配3个数字,\d{3}+ 则匹配 一个或者多个\d{3} ,连起来就是匹配以3个或者3个数字的倍数为结尾的字符串的位置。(?=xx) 是正向零宽断言,表示后面只能跟xx表达式,注意正向零宽断言也是匹配位置的。/g表示全局匹配。到这整个表达式就分析完了。概括起来整个正则就是用来匹配 非单词边界开头且以3个或者3个数字的倍数为结尾的字符串的位置。很绕吧,但是就是这么神奇,不匹配具体的字符,就是用来匹配位置的。下面再用控制权和传动分析一下具体的匹配过程。
正则表达式 /\B(?=(\d{3})+$)/g
字符串 123456789
1 第一轮匹配,首先由\B子表达式获得控制权,匹配位置0,位置0是单词边界,匹配不上,位置传动到位置1,位置1是非单词边界符,匹配成功。
2控制权交给子表达式 (?=(\d{3})+$) ,上面分析过了,这个表达式是用来匹配以3个或者3个数字的倍数为结尾的字符串的位置。位置1 后面跟的是23456789,不是3的倍数,匹配不上,传动位置到位置2,位置2后面跟的是3456789,依旧不满足,再次传动到位置3,位置三后面跟的是456789,匹配成功,也就是位置3满足条件,匹配成功。第一轮匹配结束。
3 第二轮匹配,控制权再交给\B子表达式,此时匹配就从位置4开始匹配,位置4匹配成功,再重复步骤2,位置6匹配成功,因为位置6后面跟的是789,第二轮匹配结束。
4第三轮匹配,控制权再交给\B子表达式,此时匹配就从位置7开始匹配,位置7匹配成功,再重复步骤2,因为位置7后面跟的是89,子表达式 (?=(\d{3})+$)匹配失败,至此正则匹配结束。
匹配的结果是位置3和位置6。所以123456789才会变成123,456,789
栗子2:
正则表达式/\w+?\d+/g
匹配字符串aa11bb22c3d4e5f6
匹配结果aa11 bb22 c3 d4 e5 f6
这个栗子我们就简单分析一波。
1 首先\w+? 获得控制权,量词后面跟?表示非贪婪模式,\w匹配字母、数字、下划线,\w+匹配1个或多个\w, \w+?就是尽可能少的匹配\w。首先匹配位置0,位置0后面是a,基于非贪婪模式,匹配一个a即可,位置传动到1,控制权交给\d+,位置1后面是还是a,匹配失败,正则回溯到位置0,控制权再交给\w+?,这时\w+?知道匹配一个a是不够的,所以会匹配两个a,此时位置传送到位置2,控制权交给\d+,\d+ 贪婪匹配多个数字,即匹配11,位置传送到位置4,aa11匹配成功,第一轮匹配结束。控制权再交给\w+?,如此循环往复,依次匹配出bb22 c3 d4 e5 f6。
小案例蕴含大智慧。
至此,js正则的控制权和传动就告一段落了,其中案例二中用到了回溯的概念,欢迎批评和指正,另外有正则的问题也可以留言探讨,交流才能进步,固步自封永远也无法突破知识盲区。
更详细的内容请移步:
https://www.jb51.net/article/110516.htm?winzoom=1
本文是参考这遍文章书写的,后面的案例也是之前某些地方遇到的,随手拿来分析一波。
分享一个js正则表达式校验的网站:https://regex101.com/r/DAcXTU/2,本文的案例都可以在此网站上进行测试。
网友评论