首页 > 其他分享 >正则的匹配原理以及优化原则

正则的匹配原理以及优化原则

时间:2023-09-03 22:34:19浏览次数:29  
标签:匹配 NFA 优化 正则 引擎 回溯 DFA

正则之所以能够处理复杂文本,就是因为采用了有穷状态自动机(finite automaton)。那什么是有穷自动机呢?有穷状态是指一个系统具有有穷个状态,不同的状态代表不同的意义。自动机是指系统可以根据相应的条件,在不同的状态下进行转移。从一个初始状态,根据对应的操作(比如录入的字符集)执行状态转移,最终达到终止状态(可能有一到多个终止状态)。

有穷自动机的具体实现称为正则引擎,主要有 DFA 和 NFA 两种,其中 NFA 又分为传统的 NFA 和 POSIX NFA。

DFA:确定性有穷自动机(Deterministic finite automaton)
NFA:非确定性有穷自动机(Non-deterministic finite automaton)

NFA 引擎的工作方式是,先看正则,再看文本,而且以正则为主导。 而DFA 不是这样的,DFA 会先看文本,再看正则表达式,是以文本为主导的。

一般来说,DFA 引擎会更快一些,因为整个匹配过程中,字符串只看一遍,不会发生回溯,相同的字符不会被测试两次。也就是说 DFA 引擎执行的时间一般是线性的。DFA 引擎可以确保匹配到可能的最长字符串。但由于 DFA 引擎只包含有限的状态,所以它没有反向引用功能;并且因为它不构造显示扩展,它也不支持捕获子组。

NFA  以表达式为主导,它的引擎是使用贪心匹配回溯算法实现。NFA  通过构造特定扩展,支持子组和反向引用。但由于 NFA 引擎会发生回溯,即它会对字符串中的同一部分,进行很多次对比。因此,在最坏情况下,它的执行速度可能非常慢。

因为传统的 NFA 引擎“急于”报告匹配结果,找到第一个匹配上的就返回了,所以可能会导致还有更长的匹配未被发现。比如使用正则 pos|posix 在文本 posix 中进行匹配,传统的 NFA 从文本中找到的是 pos,而不是 posix,而 POSIX NFA 找到的是 posix。

POSIX NFA 的应用很少,主要是 Unix/Linux 中的某些工具。POSIX NFA 引擎与传统的 NFA 引擎类似,但不同之处在于,POSIX NFA 在找到可能的最长匹配之前会继续回溯,也就是说它会尽可能找最长的,如果分支一样长,以最左边的为准(“The Longest-Leftmost”)。因此,POSIX NFA 引擎的速度要慢于传统的 NFA 引擎。

正则的匹配原理以及优化原则_正则

 回溯是 NFA 引擎才有的,并且只有在正则中出现量词或多选分支结构时,才可能会发生回溯。

学习了原理之后,有助于我们写出更好的正则。我们必须先保证正则的功能是正确的,然后再进行优化性能。

1、测试性能的方法

可以使用 ipython 来测试正则的性能,ipython 是一个 Python shell 增强交互工具,在 macOS/Windows/Linux 上都可以安装使用。在测试正则表达式时,它非常有用,比如下面通过一个示例,来测试在字符串中查找 abc 时的时间消耗。

In [1]: import re
In [2]: x = '-' * 1000000 + 'abc'
In [3]: timeit re.search('abc', x)
480 µs ± 8.06 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

2、提前编译好正则

编程语言中一般都有“编译”方法,我们可以使用这个方法提前将正则处理好,这样不用在每次使用的时候去反复构造自动机,从而可以提高正则匹配的性能。

3、尽量准确表示匹配范围

比如我们要匹配引号里面的内容,除了写成 “.+?” 之外,我们可以写成 “[^"]+”。使用 [^"] 要比使用点号好很多,虽然使用的是贪婪模式,但它不会出现点号将引号匹配上,再吐出的问题。

4、提取出公共部分

通过上面对 NFA 引擎的学习,相信你应该明白(abcd|abxy)这样的表达式,可以优化成ab(cd|xy),因为 NFA 以正则为主导,会导致字符串中的某些部分重复匹配多次,影响效率。

因此我们会知道th(?:is|at)要比this|that要快一些,但从可读性上看,后者要好一些,这个就需要用的时候去权衡,也可以添加代码注释让代码更容易理解。

类似地,如果是锚点,比如(^this|^that) is这样的,锚点部分也应该独立出来,可以写成比如^th(is|at) is的形式,因为锚点部分也是需要尝试去匹配的,匹配次数要尽可能少。

5、出现可能性大的放左边

由于正则是从左到右看的,把出现概率大的放左边,域名中 .com 的使用是比 .net 多的,所以我们可以写成\.(?:com|net)\b,而不是\.(?:net|com)\b。

6、只在必要时才使用子组

在正则中,括号可以用于归组,但如果某部分后续不会再用到,就不需要保存成子组。通常的做法是,在写好正则后,把不需要保存子组的括号中加上 ?: 来表示只用于归组。如果保存成子组,正则引擎必须做一些额外工作来保存匹配到的内容,因为后面可能会用到,这会降低正则的匹配性能。

7、警惕嵌套的子组重复

如果一个组里面包含重复,接着这个组整体也可以重复,比如 (.*)* 这个正则,匹配的次数会呈指数级增长,所以尽量不要写这样的正则。

8、避免不同分支重复匹配

在多选分支选择中,要避免不同分支出现相同范围的情况,上面回溯的例子中,我们已经进行了比较详细的讲解。


标签:匹配,NFA,优化,正则,引擎,回溯,DFA
From: https://blog.51cto.com/key3feng/7343597

相关文章

  • 《一般图最大匹配》学习总结
    带花树学不会,不玩了。咕掉。随机化来学随机化吧。。。实际上在随机数据上表现甚至优于带花树,不过他为什么要随机而且为什么随机就能搞我也不知道。就背一个板子就好了。点击查看代码#include<bits/stdc++.h>typedeflonglongLL;usingnamespacestd;constintMAXN=1......
  • MySQL的优化,三大范式和事务的四大特性
    优化1.对查询进行优化,要尽量避免全表扫描,首先应考虑在where及orderby涉及的列上建立索引。2.应尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全表扫描3.应尽量避免在where子句中使用notin或or或!=或<>操作符,否则将引擎放......
  • 26. 正则表达式
    一、概述  正则表达式(regularexpression)又称规则表达式,是一种文本模式(pattern)。正则表达式使用一个字符串来描述、匹配具有相同规格的字符串,通常被用来检索、替换那些符合某个模式(规则)的文本。正则表达式的核心功能就是处理文本。正则表达式并不仅限于某一种语言,但是在每种语......
  • 小程序启动耗时的优化:延迟加载和异步加载
    在开发小程序时,启动耗时是一个重要的性能指标。用户希望能够尽快地看到小程序的内容,而不是面对长时间的加载等待。为了优化启动耗时,我们可以考虑使用延迟加载和异步加载的技巧。延迟加载的概念和作用延迟加载是一种在小程序启动时,将页面内容进行分步加载的策略。它的核心思想是将页......
  • LeetCode952三部曲之二:小幅度优化(137ms -> 122ms,超39% -> 超51%)
    欢迎访问我的GitHub这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos本篇概览本文是《LeetCode952三部曲》系列之二,在前文中,咱们详细分析了解题思路,然后按照思路写出了代码,在LeetCode提交成功,成绩如下图所示,137ms,超过39%不得不说这个成绩......
  • 斜率优化DP 学习笔记
    斜率优化DP适用情况适用于求解最优解(最大、最小)问题。上凸壳与下凸壳求解步骤对于任意状态转义方程,设$A_i$,$B_i$,使状态转移方程转化为$f_i=\min(f_j+(A_i-B_j)^2)$当$i$使从$j$转移来时,丢掉$\min$$f_i=f_j+{A_i}^2+{B_j}^2-2\timesA......
  • 【DBN分类】基于北方苍鹰算法优化深度置信网络NGO-DBN实现轴承故障分类matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • 时间序列预测 | Matlab 粒子群优化长短期记忆网络(PSO-LSTM)的时间序列预测
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • 正则常见问题及解决方案
    使用正则处理问题的基本思路。有一些方法比较固定,比如将问题分解成多个小问题,每个小问题见招拆招:某个位置上可能有多个字符的话,就⽤字符组。某个位置上有多个字符串的话,就⽤多选结构。出现的次数不确定的话,就⽤量词。对出现的位置有要求的话,就⽤锚点锁定位置。如果是要查找的内容中......
  • Django优化模版拆分css文件
    Django优化模版拆分css文件可以发现前面写项目将css放在html一个文件中,虽然简单省事但是带来的问题就是文件过于冗长不方便查看和修改。这里做个分离优化提供两种方式方式一:html和css存放同一目录 将原因html中</style>内容移动到home.css文件中,然后再html移动空白位置,替换......