(推荐)JS正则知识点专题:https://www.jb51.net/article/139831.htm
正则啊,就像一座灯塔,当你在字符串的海洋不知所措的时候,总能给你一点思路;正则啊,就像一台验钞机,在你不知道用户提交的钞票真假的时候,总能帮你一眼识别;正则啊,就像一个手电筒,在你需要找什么玩意的时候,总能帮你get你要的东西...
—— 节选自 Stinson 同学的语文排比句练习《正则》
欣赏了一段文学节选后,我们正式来梳理一遍JS中的正则,本文的首要目的是,防止我经常忘记正则的一些用法,故梳理和写下来加强熟练度和用作参考,次要目的是与君共勉,如有纰漏,请不吝赐教,良辰谢过。
本文既然取题为“一条龙”,就要对得起”龙”,故将包括正则原理、语法一览、JS(ES5)中的正则、ES6对正则的扩展、实践正则的思路,我尽量深入尽量浅出地去讲这些东西(搞得好像真能深入浅出一样的),如果你只想知道怎么应用,那么看第二、三、五部分,基本就能满足你的需求了,如果想掌握JS中的正则的,那么还是委屈你跟着我的思路来吧,嘿嘿嘿!
一、原理概论
在一开始用正则的时候,就觉得神奇,计算机究竟是怎么根据一个正则表达式来匹配字符串的?直到后来我遇到了一本书叫《计算理论》,看到了正则、DFA、NFA的概念和相互间的联系,才有一些恍然小悟的意思。
但如果真的要从原理上吃透正则表达式,那么恐怕最好的方式是:
1. 首先去找一本专门讲正则的书去看看,O'REILLY的“动物总动员”系列里就有;
2. 再自己实现一个正则引擎。
而本文的重点在于JS中正则的应用,故原理仅作简单介绍(因为我也没写过正则引擎,也不深入),一来大致“糊弄下”像我一样的好奇宝宝们对正则原理的疑惑,二来知道一些原理方面基本的知识,对于理解语法和写正则是大有裨益的。
1. 正则引擎
为什么正则能有效,因为有引擎,这和为什么JS能执行一样,有JS引擎,所谓正则引擎,可以理解为根据你的正则表达式用算法去模拟一台机器,这台机器有很多状态,通过读取待测的字符串,在这些状态间跳来跳去,如果最后停在了“终结状态”(Happy Ending),那么就Say I Do,否则Say You Are a Good Man。如此将一个正则表达式转换为一个可在有限的步数中计算出结果的机器,那么就实现了引擎。
正则的引擎大致可分为两类:DFA和NFA
1. DFA (Deterministic finite automaton) 确定型有穷自动机
2. NFA (Non-deterministic finite automaton) 非确定型有穷自动机,大部分都是NFA
这里的“确定型”指,对于某个确定字符的输入,这台机器的状态会确定地从a跳到b,“非确定型”指,对于某个确定字符的输入,这台机器可能有好几种状态的跳法;这里的“有穷”指,状态是有限的,可以在有限的步数内确定某个字符串是被接受还是发好人卡的;这里的“自动机”,可以理解为,一旦这台机器的规则设定完成,就可以自行判断了,不要人看。
DFA引擎不需要进行回溯,所以匹配效率一般情况下要高,但是它并不支持捕获组,于是也就不支持反向引用和$这种形式的引用,也不支持环视(Lookaround)、非贪婪模式等一些NFA引擎特有的特性。
如果想更详细地了解正则、DFA、NFA,那么可以去看一下《计算理论》,然后你可以根据某个正则表达式自己画出一台自动机。
2. 知识储备
这一小节对于你理解正则表达式很有用,尤其是明白什么是字符,什么是位置。
2.1 正则眼中的字符串——n个字符,n+1个位置
在上面的“笑声”字符串中,一共有8个字符,这是你能看到的,还有9个位置,这是聪明的人才能看到的。为什么要有字符还要有位置呢?因为位置是可以被匹配的。
那么进一步我们再来理解“占有字符”和“零宽度”:
如果一个子正则表达式匹配到的是字符,而不是位置,而且会被保存到最终的结果中,那个这个子表达式就是占有字符的,比如/ha/(匹配ha)就是占有字符的;
如果一个子正则匹配的是位置,而不是字符,或者匹配到的内容不保存在结果中(其实也可以看做一个位置),那么这个子表达式是零宽度的,比如/read(?=ing)/(匹配reading,但是只将read放入结果中,下文会详述语法,此处仅仅举例用),其中的(?=ing)就是零宽度的,它本质代表一个位置。