正则表达式入门课
涂伟忠
高级研发工程师
24700 人已学习
新⼈⾸单¥59
登录后,你可以任选2讲全文学习
课程目录
已完结/共 18 讲
正则表达式入门课
15
15
1.0x
00:00/00:00
登录|注册

11 | 如何理解正则的匹配原理以及优化原则?

避免不同分支重复匹配
警惕嵌套的子组重复
只在必要时才使用子组
出现可能性大的放左边
提取出公共部分
尽量准确表示匹配范围
提前编译好正则
测试性能的方法
示例:回溯的影响
回溯在NFA引擎中的作用
POSIX NFA引擎特点
DFA引擎工作方式
NFA引擎工作方式
匹配过程示例
生成自动机
编译正则表达式
系统可以根据条件进行状态转移
系统具有有穷个状态
课后思考
总结
优化建议
回溯
POSIX NFA 与 传统 NFA 区别
DFA & NFA 工作机制
正则的匹配过程
有穷状态自动机
如何理解正则的匹配原理、优化原则

该思维导图由 AI 生成,仅供参考

你好,我是伟忠,这一节课我们一起来学习正则匹配原理相关的内容,以及在书写正则时的一些优化方法。
这节课我主要给你讲解一下正则匹配过程,回顾一下之前讲的回溯,以及 DFA 和 NFA 引擎的工作方式,方便你明白正则是如何进行匹配的。这些原理性的知识,能够帮助我们快速理解为什么有些正则表达式不符合预期,也可以避免一些常见的错误。只有了解正则引擎的工作原理,我们才可以更轻松地写出正确的,性能更好的正则表达式。

有穷状态自动机

正则之所以能够处理复杂文本,就是因为采用了有穷状态自动机(finite automaton)。那什么是有穷自动机呢?有穷状态是指一个系统具有有穷个状态,不同的状态代表不同的意义。自动机是指系统可以根据相应的条件,在不同的状态下进行转移。从一个初始状态,根据对应的操作(比如录入的字符集)执行状态转移,最终达到终止状态(可能有一到多个终止状态)。
有穷自动机的具体实现称为正则引擎,主要有 DFA 和 NFA 两种,其中 NFA 又分为传统的 NFA 和 POSIX NFA。
DFA:确定性有穷自动机(Deterministic finite automaton)
NFA:非确定性有穷自动机(Non-deterministic finite automaton)
接下来我们来通过一些示例,来详细看下正则表达式的匹配过程。

正则的匹配过程

在使用到编程语言时,我们经常会“编译”一下正则表达式,来提升效率,比如在 Python3 中它是下面这样的:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入介绍了正则表达式的匹配原理和优化原则。首先讲解了有穷状态自动机的概念,以及正则引擎中的DFA和NFA两种实现方式。详细讲解了正则的匹配过程,以及NFA和DFA引擎的工作机制的区别。文章还介绍了POSIX NFA与传统NFA的区别,以及它们在匹配过程中的特点。此外,提供了一些优化建议,如测试性能的方法、提前编译好正则、尽量准确表示匹配范围等。总的来说,本文内容丰富,适合想要深入了解正则表达式的读者。文章通过举例和实际应用,使读者能够更好地理解和应用正则表达式。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《正则表达式入门课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(19)

  • 最新
  • 精选
  • 看了一下这个匹配过程分为几步: 1: 拿到正则表达式的 开始符号 ^, 去匹配字符串的开始 2: 拿到正则的 (?=[a-z]) ,发现是一个环视,不进行看字符串 3: 解析环视中的 表达式为:[a-z],和下一个字符串进行比较,发现找到了a符合要求 4: 继续取下一部分的正则为: [a-z0-9]+ ,和接下来的字符串进行比较,贪婪模式,匹配到字符串结尾 5: 取出正则的 $ 和字符串进行比较,判断是否是结尾

    作者回复: 没什么问题,环视只匹配位置,是零宽度的,区别就在于这儿。 元字符“^”和“$”匹配的只是位置,顺序环视“(?=[a-z])”只进行匹配,并不占有字符,也不将匹配的内容保存到最终的匹配结果,所以都是零宽度的。 匹配过程: 首先由元字符“^”取得控制权,从位置0开始匹配,“^”匹配的就是开始位置“位置0”,匹配成功,控制权交给顺序环视“(?=[a-z])”; “(?=[a-z])”要求它所在位置右侧必须是字母才能匹配成功,零宽度的子表达式之间是不互斥的,即同一个位置可以同时由多个零宽度子表达式匹配,所以它也是从位置0尝试进行匹配,位置0的右侧是字符“a”,符合要求,匹配成功,控制权交给“[a-z0-9]+”; 因为“(?=[a-z])”只进行匹配,并不将匹配到的内容保存到最后结果,并且“(?=[a-z])”匹配成功的位置是位置0,所以“[a-z0-9]+”也是从位置0开始尝试匹配的,“[a-z0-9]+”首先尝试匹配“a”,匹配成功,继续尝试匹配,可以成功匹配接下来的“1”和“2”,此时已经匹配到位置3,位置3的右侧已没有字符,这时会把控制权交给“$”; 元字符“$”从位置3开始尝试匹配,它匹配的是结束位置,也就是“位置3”,匹配成功。 此时正则表达式匹配完成,报告匹配成功。匹配结果为“a12”,开始位置为0,结束位置为3。其中“^”匹配位置0,“(?=[a-z])”匹配位置0,“[a-z0-9]+”匹配字符串“a12”,“$”匹配位置3。 可以参考 https://blog.csdn.net/lxcnn/article/details/4304651

    2020-07-08
    13
  • Robot
    文本:a12 正则:^(?=[a-z])[a-z0-9]+$ 1、正则^先开始匹配到a12的开始位置 2、正则(?=[a-z])正向环视检查,开始位置之后的字符是否是a-z之一,匹配 3、正则[a-z0-9]+依次匹配a12,直到$匹配不上终止 4、回溯到$之前的位置,正则$开始匹配,匹配完成

    作者回复: 对的

    2020-07-08
    2
  • Bug? Feature!
    提前编译好正则,提取出公共部分,尽量准确地表示范围,必要时才使用子组等。

    作者回复: 对的

    2020-10-23
    1
  • Sola
    终于弄清楚为啥 环视又叫 「零宽度」了,就是想表达这个只是匹配位置,这里的「零宽度」 指的是不占用匹配宽度,匹配测试之后会退回到之前的位置。奇怪的命名增加了很多的理解成本

    作者回复: :-D

    2020-10-11
    1
  • Regina
    DFN引擎匹配那,为什么是shixi被淘汰而不是shijian text: we study on jikeshixi app ^ regex: jike(zhushou|shijian|shixi) ^ ^ 符合 淘汰

    作者回复: 感谢指出,这里DFA部分,文本应该是 we study on jikeshijian app

    2020-07-21
    1
  • NFA 通过构造特定扩展,支持子组和反向引用 ----------------------------- 这里的扩展是什么意思? 指什么

    作者回复: 你可以理解成NFA可以把匹配到的内容记下来,“扩展”可以理解成做了一些额外的工作。 原理部分最主要的是理解DFA的“文本主导”,NFA“正则主导”以及回溯相关的内容。

    2020-07-08
    1
  • 洪涛
    你可以理解成 a(bb)+a 在匹配了字符 abb 之后,到底在 s3 状态,还是在 s1 状态,这是不确定的。这句话还是没懂。。麻烦解释下

    作者回复: 就是bb重复多次的时候,状态机s3流转到s1不需要额外条件,“根据需要”去选择,具体是哪个,是不确定的

    2021-11-14
  • charming-kamly
    请教一下, 确定和非确定应该怎么理解?

    作者回复: 文中有解释。 在状态 s3 时,不需要输入任何字符,状态也有可能转换成 s1。你可以理解成 a(bb)+a 在匹配了字符 abb 之后,到底在 s3 状态,还是在 s1 状态,这是不确定的。这种状态机就是非确定性有穷状态自动机(Non-deterministic finite automaton 简称 NFA)。

    2021-03-21
  • 吴小智
    NFA 有 ε 的状态转移,但是 DFA 没有。

    作者回复: NFA功能要多一些,复杂一些。 DFA简单,速度快

    2020-07-24
  • 简简单单
    [^"] : 在中括号中表示 非双引号的所有字符吗? ^" : 在非中括号中表示 必须是行头, 且行头右侧第一个字符必须是个双引号吗 ?

    作者回复: 对的,理解正确,在正则开头 和 在中括号里面第一个位置是含义不一样

    2020-07-22
收起评论
显示
设置
留言
19
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部