Skip to content

正则表达式学习笔记(二) #7

Description

@Janking

前言

最近在重新学习正则表达式,把在学习过程中所遇到的案例,还有比较难理解概念用自己的理解分析并整理总结。

如有哪些地方不对,欢迎指正,谢谢!(๑•ᴗ•๑)

本系列使用的JavaScript所支持的正则表达式语法,并推荐你使用 http://regexr.com/ 去做相应的练习。

假定你已经熟悉元字符方括号修饰符,量词RegExp对象

如果没有,请先看一遍文档
http://www.w3school.com.cn/jsref/jsref_obj_regexp.asp

本系列同步GitHub https://github.com/Janking/Blog/issues

系列目录

正则表达式案例分析 (一)

案例分析

(1) 重复分组

在上一篇介绍千分位的时候,就有用到重复分组,这是一个很容易理解错误的点,至少我开始的时候是理解错误的。

https://user-gold-cdn.xitu.io/2017/7/23/0752787423b4fe0c5aaa52f2126294ba

假定用这个正则去匹配 1234567890,开始我以为分组小括号(\d\d\d)的最终结果是 123456789都能拿到,但结果却只有789

重复分组的匹配在每次引擎退出该分组的时候被捕获,并会覆盖该分组在之前匹配的任何文本

模拟一下引擎工作的步骤:

1. 第一次匹配,捕获到 `123`,退出分组
2. 第二次匹配,捕获到 `456`, 覆盖上一次捕获的`123`,退出分组
3. 第三次匹配,捕获到 `789`,覆盖上一次捕获的`456`,退出分组
4. 退出重复分组,结束

因为重复分组最后一次循环存储的是789,另外两次分组匹配,也就是123,456是无法被获取的。

如果想要获得所有结果,就要把重复匹配放进分组中 /((\d\d\d){3})/

(2) 获取<p>...</p>中的内容

https://user-gold-cdn.xitu.io/2017/7/23/92b63477e6366c36f7dac825f3bda438

/<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(非确定型有限自动机),匹配慢,编译快。

结束语

本章节将的案例只有两个,主要是涉及到几个重要概念,占了一定的篇幅,由于本人不喜欢把文章写的太长,影响阅读体验,所以就此打住,从下一篇开始会重点的去分析常用正则表达式的匹配过程,敬请期待。

参考文献:

  • 《精通正则表达式》
  • 《正则表达式经典实例》

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions