使用正则表达式时-可能会导致性能下降的情况

目录

前言

正则表达式引擎

NFA自动机的回溯

解决方案


  • 前言

  • 正则表达式是一个用正则符号写出的公式,程序对这个公式进行语法分析,建立一个语法分析树,再根据这个分析树结合正则表达式的引擎生成执行程序(这个执行程序我们把它称作状态机,也叫状态自动机),用于字符匹配
  • 使用不恰当的正则表达式可能会导致很严重的性能问题
  • 比如:

  • 这个正则表达式看起来没什么问题,它可以分为三个部分:
  • 第一部分匹配 http 和 https 协议,第二部分匹配 www. 字符,第三部分匹配许多字符
  • 其实这里会导致 CPU 使用率高的关键原因就是:Java 正则表达式使用的引擎实现是 NFA 自动机,这种正则表达式引擎在进行字符匹配时会发生回溯backtracking
  • 而一旦发生回溯,那其消耗的时间就会变得很长,有可能是几分钟,也有可能是几个小时,时间长短取决于回溯的次数和复杂度
  • 正则表达式引擎

  • 正则表达式引擎就是一套核心算法,用于建立状态机
  • 简单地说,实现正则表达式引擎的有两种方式:DFA 自动机(Deterministic Final Automata 确定型有穷自动机)和 NFA 自动机(Non deterministic Finite Automaton 不确定型有穷自动机)
  • 简单来讲,NFA 对应的是正则表达式主导的匹配,而 DFA 对应的是文本主导的匹配
  • 简单来讲,DFA 自动机的时间复杂度是线性的,更加稳定,但是功能有限;而 NFA 的时间复杂度比较不稳定,有时候很好,有时候不怎么好,好不好取决于你写的正则表达式;但是胜在 NFA 的功能更加强大,所以包括 Java、.NET、Perl、Python、Ruby、PHP 等语言都使用了 NFA 去实现其正则表达式
  • 那 NFA 自动机到底是怎么进行匹配的呢?我们以下面的字符和表达式来举例说明:

  • 要记住一个很重要的点,即:NFA 是以正则表达式为基准去匹配的
  • 也就是说,NFA 自动机会读取正则表达式的一个一个字符,然后拿去和目标字符串匹配,匹配成功就换正则表达式的下一个字符,否则继续和目标字符串的下一个字符比较
    • 首先,拿到正则表达式的第一个匹配符:d
    • 于是拿去和字符串的字符进行比较,字符串的第一个字符是T,不匹配,换下一个
    • 第二个是o,也不匹配,再换下一个
    • 第三个是d,匹配了,那么就读取正则表达式的第二个字符:a
    • 读取到正则表达式的第二个匹配符:a
    • 拿着继续和字符串的第四个字符 a 比较,又匹配了
    • 那么接着读取正则表达式的第三个字符:y
    • 读取到正则表达式的第三个匹配符:y
    • 拿着继续和字符串的第五个字符 y 比较,又匹配了
    • 尝试读取正则表达式的下一个字符,发现没有了,那么匹配结束
  • 上面这个匹配过程就是 NFA 自动机的匹配过程,但实际上的匹配过程会比这个复杂非常多,但其原理是不变的
  • NFA自动机的回溯

  • 了解了 NFA 是如何进行字符串匹配的,接下来我们就可以讲讲这篇文章的重点了:回溯
  • 为了更好地解释回溯,我们同样以下面的例子来讲解:

  • 上面的这个例子的目的比较简单,匹配以 a 开头,以 c 结尾,中间有 1-3 个 b 字符的字符串
  • NFA 对其解析的过程是这样子的:
    • 首先,读取正则表达式第一个匹配符 a 和 字符串第一个字符 a 比较,匹配了
    • 于是读取正则表达式第二个字符
    • 读取正则表达式第二个匹配符 b{1,3} 和字符串的第二个字符 b 比较,匹配了
    • 但因为 b{1,3} 表示 1-3 个 b 字符串,以及 NFA 自动机的贪婪特性(也就是说要尽可能多地匹配),所以此时并不会再去读取下一个正则表达式的匹配符,而是依旧使用 b{1,3} 和字符串的第三个字符 b 比较,发现还是匹配
    • 于是继续使用 b{1,3} 和字符串的第四个字符 c 比较,发现不匹配了
    • 此时就会发生回溯
    • 发生回溯是怎么操作呢?
    • 发生回溯后,我们已经读取的字符串第四个字符 c 将被吐出去,指针回到第三个字符串的位置
    • 之后,程序读取正则表达式的下一个操作符 c,读取当前指针的下一个字符 c 进行对比,发现匹配
    • 于是读取下一个操作符,但这里已经结束了
  • 下面我们回过头来看看前面的那个校验 URL 的正则表达式:

  • 出现问题的 URL 是:

  • 我们把这个正则表达式分为三个部分:
    • 第一部分:校验协议;^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)
    • 第二部分:校验域名;(([A-Za-z0-9-~]+).)+
    • 第三部分:校验参数;([A-Za-z0-9-~\\/])+$
  • 我们可以发现正则表达式校验协议 http:// 这部分是没有问题的,但是在校验 www.fapiao.com 的时候,其使用了 xxxx. 这种方式去校验
  • 那么匹配过程是这样的:
    • 匹配到 www.
    • 匹配到 fapiao.
    • 匹配到 com/dzfp-web/pdf/download?request=6e7JGm38jf.....,你会发现因为贪婪匹配的原因,所以程序会一直读后面的字符串进行匹配,最后发现没有点号,于是就一个个字符回溯回去了
  • 这是这个正则表达式存在的第一个问题
  • 另外一个问题是在正则表达式的第三部分,我们发现出现问题的 URL 是有下划线(_)和百分号(%)的,但是对应第三部分的正则表达式里面却没有
  • 这样就会导致前面匹配了一长串的字符之后,发现不匹配,最后回溯回去
  • 这是这个正则表达式存在的第二个问题
  • 解决方案

  • 明白了回溯是导致问题的原因之后,其实就是减少这种回溯,你会发现如果我在第三部分加上下划线和百分号之后,程序就正常了

  • 运行上面的程序,立刻就会打印出match!!
  • 但这是不够的,如果以后还有其他 URL 包含了乱七八糟的字符呢,我们难不成还再修改一遍
  • 肯定不现实
  • 其实在正则表达式中有这么三种模式:贪婪模式、懒惰模式、独占模式
  • 在关于数量的匹配中,有 + ? * {min,max} 四种两次,如果只是单独使用,那么它们就是贪婪模式
  • 如果在他们之后多加一个 ? 符号,那么原先的贪婪模式就会变成懒惰模式,即尽可能少地匹配
  • 但是懒惰模式还是会发生回溯现象
  • 例如下面这个例子:

  • 正则表达式的第一个操作符 a 与 字符串第一个字符 a 匹配,匹配成功
  • 于是正则表达式的第二个操作符 b{1,3}? 和 字符串第二个字符 b 匹配,匹配成功
  • 因为最小匹配原则,所以拿正则表达式第三个操作符 c 与字符串第三个字符 b 匹配,发现不匹配
  • 于是回溯回去,拿正则表达式第二个操作符 b{1,3}? 和字符串第三个字符 b 匹配,匹配成功
  • 于是再拿正则表达式第三个操作符 c 与字符串第四个字符 c 匹配,匹配成功;于是结束
  • 如果在他们之后多加一个 + 符号,那么原先的贪婪模式就会变成独占模式,即尽可能多地匹配,但是不回溯
  • 于是乎,如果要彻底解决问题,就要在保证功能的同时确保不发生回溯
  • 将上面校验 URL 的正则表达式的第二部分后面加多了个 + 号,即变成这样:

  • 这样之后,运行原有的程序就没有问题了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/196682.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

初步认识结构体

hello,hello,各位小伙伴,本篇文章跟大家一起学习结构体,并跟大家一边做题一边进行学习和理解。感谢大家对我上一篇的支持,如有什么问题,还请多多指教! 如果本篇文章对你有帮助,还请…

贝叶斯网络 (人工智能期末复习)

文章目录 贝叶斯网络(概率图模型)定义主要考点例题- 要求画出贝叶斯网络图- 计算各节点的条件概率表- 计算概率- 分析独立性 贝叶斯网络(概率图模型) 定义 一种简单的用于表示变量之间条件独立性的有向无环图(DAG&am…

BGP基本配置

一、知识补充 1、BGP BGP是Border Gateway Protocol(边界网关协议)的缩写。它是用于在互联网中交换路由信息的一种协议。BGP被广泛应用于大规模的自治系统(AS)之间,用于实现跨网络的路由选择和交换。 BGP的主要功能…

基于Cocos2D-X框架闯关游戏的设计

摘 要 随着智能设备平台的普及、用户数量的增多,智能平台的应用,尤其是游戏异常火爆,从植物大战僵尸到愤怒的小鸟,移动平台游戏的开发进入了新的阶段。但是另一方面,平台的多样性也给开发者带来诸多不便,怎…

单片机第三季-第四课:STM32下载、MDK和调试器

目录 1,扩展板使用的STM32芯片类型 2,使用普中科技软件下载程序 3,keil介绍 4,JLINK调试器介绍 5,使用普中的调试器进行debug 6,使用Simulator仿真 1,扩展板使用的STM32芯片类型 扩展版…

什么是网络可视化?网络可视化工具有用吗

网络可视化定义是自我描述的,因为它在单个屏幕上重新创建网络布局,以图形和图表的形式显示有关网络设备、网络指标和数据流的信息,为 IT 运营团队提供一目了然的理解和决策。 网络是复杂的实体,倾向于持续进化,随着业…

【C++】异常处理 ⑧ ( 标准异常类 | 标准异常类继承结构 | 常用的标准异常类 | 自定义异常类继承 std::exception 基类 )

文章目录 一、抛出 / 捕获 多个类型异常对象1、标准异常类2、标准异常类继承结构3、常用的标准异常类 二、自定义异常类继承 std::exception 基类1、自定义异常类继承 std::exception 基类2、完整代码示例 - 自定义异常类继承 std::exception 基类 一、抛出 / 捕获 多个类型异常…

java常用知识点记忆

类的继承与多态 类的继承不支持多重继承非private 方法才可以被覆盖覆盖的方法要求,子类中的方法的名字,参数列表,返回类型与父类相同方法的重载是在一个类中定义方法名字相同,但是参数列表不同的方法要是在子类中定义了与父类名字…

【Windows】使用SeaFile搭建本地私有云盘并结合内网穿透实现远程访问

1. 前言 现在我们身边的只能设备越来越多,各种智能手机、平板、智能手表和数码相机充斥身边,需要存储的数据也越来越大,一张手机拍摄的照片都可能有十多M,电影和视频更是按G计算。而智能设备的存储空间也用的捉襟见肘。能存储大量…

JDBC常见的几种连接池使用(C3P0、Druid、HikariCP 、DBCP)(附上代码详细讲解)

Hi i,m JinXiang ⭐ 前言 ⭐ 本篇文章主要介绍JDBC常见的几种连接池使用(C3P0、Druid、HikariCP 、DBCP)以及部分理论知识 🍉欢迎点赞 👍 收藏 ⭐留言评论 📝私信必回哟😁 🍉博主收将持续更新学…

开启全新消费革命——消费增值,让每一笔消费变成财富!

你是否厌倦了仅仅购买物品或享受服务后便一无所有的消费方式?现在,消费增值的概念将彻底改变你的消费观念!通过参与消费增值,你的每一笔消费都将变得更有价值! 消费增值是一种全新的消费理念,它让你在购物的…

tex中的边框

文章目录 利用tcolorbox宏包给公式加框 利用tcolorbox宏包 tcolorbox可以创建一个盒子的环境,例如: \documentclass{article} \usepackage{tcolorbox} \begin{document}\begin{tcolorbox}[left1cm, right1cm, top0.5cm, bottom0.5cm,colbackblue!10!wh…

CSRF之pikachu靶场DW

1,登录皮卡丘靶场,get请求; 2,抓包并修改标记后的个人信息 最后放通一下,发现账号信息被修改 2,post请求 1提交post数据并使用bp抓包 2.利用工具改包,并生成url 3,点击提交后&#…

SpringBoot自定义异常处理机制

说明:在完整的项目结构中,我们通常会创建一个自定义的异常处理机制,在系统可能出现异常的地方手动抛出这些异常,可以快速定位到异常代码片段,提供项目的可维护性。 本文介绍在SpringBoot项目中,搭建一套自…

ssm党务政务服务热线平台源码和论文答辩PPT

摘要 首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要包罗软件架构模式、整体功能模块、数据库设计…

任意密码重置+CRRF

一、XSS漏洞 在商城的搜索处,输入标准语句的传参直接就可以弹窗 二、逻辑漏洞-用户枚举 在用户注册界面,点击发送验证码,然后用BURP发包 更改手机号传参,这里手机号传参没有进行加密,直接用手机号的位置进行爆破 正确的…

LeetCode力扣每日一题(Java):9、回文数

一、题目 二、解题思路 1、我的思路 当x<0时&#xff0c;x一定不是回文数&#xff0c;直接返回false 当x>0且x<10时&#xff0c;x一定是回文数&#xff0c;直接返回true x>10时&#xff0c;先将x转为字符串。将数字转成字符串方法挺多的&#xff0c;以下是&…

06、基于内容的过滤算法Tensorflow实现

06、基于内容的过滤算法Tensorflow实现 开始学习机器学习啦&#xff0c;已经把吴恩达的课全部刷完了&#xff0c;现在开始熟悉一下复现代码。全部工程可从最上方链接下载。 05、基于梯度下降的协同过滤算法中已经介绍了协同过滤算法的基本实现方法&#xff0c;但是这种方法仅…

SpringBoot集成i18n(多语言)

配置文件 spring: messages: basename: il8n/messages # 配置国际化资源文件路径 fallback-to-system-locale: true # 是否使用系统默认的语言环境作为备选项 国际化配置 import org.springframework.context.annotation.Bean; import org.spr…

MySQL-宋红康-(课P14-P15)-基本查询语句(Select)

b站视频&#xff1a; 14-最基本的SELECT...FROM结构_哔哩哔哩_bilibili 8.4 基本查询(Select)语句 数据table: emp员工表创建如下 # 员工表 CREATE TABLE EMP (EMPNO INT PRIMARY KEY, -- 员工编号ENAME VARCHAR(10), -- 员工名称JOB VARCHAR(9), -- 工…