最近在从新学习正则表达式,把在学习过程当中所遇到的案例,还有比较难理解概念用本身的理解分析并整理总结。git
若有哪些地方不对,欢迎指正,谢谢!(๑•ᴗ•๑)github
本系列使用的JavaScript
所支持的正则表达式语法,并推荐你使用 regexr.com/ 去作相应的练习。正则表达式
假定你已经熟悉元字符
,方括号
,修饰符
,量词
及RegExp对象
。bash
若是没有,请先看一遍文档
www.w3school.com.cn/jsref/jsref…post
本系列同步GitHub github.com/Janking/Blo…学习
在上一篇介绍千分位的时候,就有用到重复分组,这是一个很容易理解错误的点,至少我开始的时候是理解错误的。code
假定用这个正则去匹配 1234567890
,开始我觉得分组小括号(\d\d\d)
的最终结果是 123
,456
,789
都能拿到,但结果却只有789
regexp
重复分组的匹配在每次引擎退出该分组的时候被捕获,并会覆盖该分组在以前匹配的任何文本cdn
模拟一下引擎工做的步骤:
1. 第一次匹配,捕获到 `123`,退出分组
2. 第二次匹配,捕获到 `456`, 覆盖上一次捕获的`123`,退出分组
3. 第三次匹配,捕获到 `789`,覆盖上一次捕获的`456`,退出分组
4. 退出重复分组,结束复制代码
由于重复分组最后一次循环存储的是789,另外两次分组匹配,也就是123,456是没法被获取的。
若是想要得到全部结果,就要把重复匹配放进分组中 /((\d\d\d){3})/
<p>...</p>
中的内容/<p>(.*?)<\/p>/g.exec('<p>Hello,<em>world</em></p><p>Hello,Janking</p>')
[
"<p>Hello,<em>world</em></p>",
"Hello,<em>world</em>",
index: 0,
input: "<p>Hello,<em>world</em></p><p>Hello,Janking</p>"
]复制代码
假如没有?
,而匹配结果就会差很远,不信你看!
/<p>(.*)<\/p>/g.exec('<p>Hello,<em>world</em></p><p>Hello,Janking</p>')
[
"<p>Hello,<em>world</em></p><p>Hello,Janking</p>",
"Hello,<em>world</em></p><p>Hello,Janking",
index: 0,
input: "<p>Hello,<em>world</em></p><p>Hello,Janking</p>"
]复制代码
缺乏了问号?
,结果把中间的</p><p>
也匹配进来了,为何一个字符不一样,匹配结果就差别那么大?这里涉及到正则表达式中比较重要的概念:贪婪匹配,懒惰匹配,回溯
属于贪婪模式的量词,也叫作匹配优先量词,包括:{m,n}
,{m,}
,?
,*
和 +
。
在匹配优先量词后加上?
,即变成属于惰性匹配的量词,也叫作忽略优先量词,包括:{m,n}?
,{m,}?
,??
,*?
和 +?
。
当前前面分支/重复匹配成功后,没有多余的文本可被正则后半部分匹配时,会产生回溯
用一个简单的例子来解释一下贪婪匹配和惰性匹配!
贪婪 : /\d+\b/
惰性 : /d+?\b/
文本 : 1234a
贪婪正则匹配 1234a
时的过程是这样的:
1. \d+ 匹配获得 1234
2. \b 却匹配失败,由于它的左边必须是数字,而不是字母 (\b 是分词边界匹配,用来获取位置,而不是文本,上一节有讲到)
4. 这个时候,\d+会尝试回吐一个字符,即匹配结果为 123 ,可\b仍是匹配失败!
5. 那就继续回吐,一直到 1,仍是匹配失败,那么这个正则就总体匹配失败了
6. 这个回吐匹配结果的过程就是回溯复制代码
惰性正则匹配 1234a
时的过程是这样的:
1. \d+? 首先匹配,结果是 1 ,紧接着 \b 匹配失败
2. 那就 \d+? 继续匹配,结果是 12 ,紧接着 \b 仍是匹配失败
3. \d+? 一直匹配到1234,紧接着的 \b 依然匹配失败
4. 结果整个正则匹配不成功复制代码
经过这两个例子的比较,相信你会猜到回溯会影响匹配速度,回溯的过程慢那是相对那些DFA引擎。
而JS的正则引擎是NFA(非肯定型有限自动机),匹配慢,编译快。
本章节将的案例只有两个,主要是涉及到几个重要概念,占了必定的篇幅,因为本人不喜欢把文章写的太长,影响阅读体验,因此就此打住,从下一篇开始会重点的去分析经常使用正则表达式的匹配过程,敬请期待。