关于正则表达式,这篇都讲清楚了
作者 | 猪哥
来源 | 裸睡的猪(ID:rgznai100)
目前越来越多的网站、编辑器、编程语言都已支持一种叫“正则表达式”的字符串查找“公式”,有过编程经验的同学都应该了解正则表达式(Regular Expression 简写regex)是什么东西,它是一种字符串匹配的模式(pattern),更像是一种逻辑公式。
使用正则表达式去匹配字符串Hello World 中的 Hello
伪代码:/Hello/, "Hello World"
输出:Hello
如何写好一篇关于 正则表达式 的文章,我思考了一周的时间,从未有一篇文章能让猪哥如此费神。
因为我觉得正则表达式 :难记忆、难描述、广而深且不受重视,有人说正则表达式既好写也难写!
好写:无非写一些常用、实用的案例,说实话你们每个人都能写出这种:在网上百度一下然后结合一点自己的实际经验,一篇文章就出来了。
难写:很多人都认为正则简单,不用记,要用就百度一下。但是绝大多数人了解的只是正则的一个小面,真正的精髓却很少关注!
希望大家能知道正则的知识点其实非常非常多,尤其是正则引擎执行原理以及正则优化,这算是正则表达式的进阶知识点,面试中也可能会被问到。
起源与发展
我们在学习一门技术的时候有必要了解其起源与发展过程,这对我们去理解技术本身有一定的帮助!
20世纪40年代:正则表达式最初的想法来自两位神经学家:沃尔特·皮茨与麦卡洛克,他们研究出了一种用数学方式来描述神经网络的模型。
1956年:一位名叫Stephen Kleene的数学科学家发表了一篇题目是《神经网事件的表示法》的论文,利用称之为正则集合的数学符号来描述此模型,引入了正则表达式的概念。正则表达式被作为用来描述其称之为“正则集的代数”的一种表达式,因而采用了“正则表达式”这个术语。
1968年:C语言之父、UNIX之父肯·汤普森把这个“正则表达式”的理论成果用于做一些搜索算法的研究,他描述了一种正则表达式的编译器,于是出现了应该算是最早的正则表达式的编译器qed(这也就成为后来的grep编辑器)。
Unix使用正则之后,正则表达式不断的发展壮大,然后大规模应用于各种领域,根据这些领域各自的条件需要,又发展出了许多版本的正则表达式,出现了许多的分支。我们把这些分支叫做“流派”。
1987年:Perl语言诞生了,它综合了其他的语言,用正则表达式作为基础,开创了一个新的流派,Perl流派。之后很多编程语言如:Python、Java、Ruby、.Net、PHP等等在设计正则式支持的时候都参考Perl正则表达式。
到这里我们也就知道为什么众多编程语言的正则表达式基本一样,因为他们都师从Perl。
注:Perl语言是一种擅长处理文本的语言,但因晦涩语法和古怪符号不利于理解和记忆导致很多开发者并不喜欢。
语法
完整的正则表达式由两种字符构成:特殊字符(元字符)和普通字符。
ps:元字符表示正则表达式功能的最小单位,如 *
^
$
\d
等等
关于语法部分猪哥并不想过多的讲解,给大家做一个详细的归纳整理,供大家日后快速查找吧!
如果想系统学习正则表达式的语法部分,猪哥推荐 菜鸟教程: https://www.runoob.com/regexp/regexp-tutorial.html
匹配原理
匹配原理是猪哥想要重点讲解的部分,也希望同学们可以认真了解这部分的内容。
很多人觉得开车没必要了解车的构造原理,但是我们学编程的还真的需要了解原理。
因为了解原理,你才能调优,这往往也是初级工程师与中高级工程师之间的差别点之一!
1.执行过程
正则表达式的执行,是由正则表达引擎编译执行的,大致的执行流程猪哥也画了个流程图给大家看看。
这里给大家提一点就是:预编译(pre-use compile)
猪哥建议大家在生产环境中使用预编译功能,为什么呢?
以Python语言内置re
模块举例:
通过
re.compile(pattern)
预编译返回Pattern对象,在后面代码中可以直接引用。通过
re.match(pattern, text)
即用编译,虽然也会有缓存Pattern对象,但是每次使用都需要去缓存中取出,比预编译多一步取操作。
猪哥也通过实际测试来 验证预编译 确实比 即用编译 要快!
pattern = r'http:\/\/(?:.?\w+)+'text = '<a href="http://www.xxx.com">xxx.com</a>'
2.引擎(重点)
既然正则表达式由执行引擎执行,那我们就来讲讲正则表达式的引擎吧,这一块是重点,希望大家仔细看看,弄懂了理解了才行!
正则引擎主要可以分为基本不同的两大类:
DFA (Deterministic finite automaton) 确定型有穷自动机
NFA (Non-deterministic finite automaton) 非确定型有穷自动机
ps:当然还有一种引擎为:POSIX NFA,这是根据NFA引擎出的规范版本,但因为使用较少所以我们这里也就不重点讲解。
这里需要和大家解释下何为确定型
、有穷
、自动机
这几个名词:
确定型与非确定型:假设有一个字符串(text=abc)需要匹配,在没有编写正则表达式的前提下,就直接可以确定字符匹配顺序的就是确定型,不能确定字符匹配顺序的则为非确定型。
有穷:有穷即表示有限的意思,这里表示有限次数内能得到结果。
自动机:自动机便是自动完成,在我们设置好匹配规则后由引擎自动完成,不需要人为干预!
根据上面的解释我们可得知DFA引擎 和 NFA引擎 的一个很大区别就是:在没有编写正则表达式的前提下,是否能确定字符执行顺序!
DFA引擎执行原理:
为了大家能很清楚的理解DFA引擎执行原理,猪哥制作了一个简易的动态执行过程图给大家看看
根据上面的动图我们可以得出DFA引擎的一些特点:
文本主导:按照文本的顺序执行,这也就能说明为什么DFA引擎是确定型(deterministic)了,稳定!
记录当前有效的所有可能:我们看到当执行到
(d|b)
时,同时比较表达式中的d
和b
,所以会需要更多的内存。每个字符只检查一次:这提高了执行效率,而且速度与正则表达式无关。
不能使用反向引用等功能:因为每个字符只检查一次,文本零宽度(位置)只记录当前比较值,所以不能使用反向引用、环视等一些功能!
NFA引擎执行原理:
猪哥同样画了一个简易的NFA引擎执行过程图方便大家理解
根据上面的动图我们可以得出NFA引擎的一些特点:
文表达式主导:按照表达式的一部分执行,如果不匹配换其他部分继续匹配,直到表达式匹配完成。
会记录某个位置:我们看到当执行到
(d|b)
时,NFA引擎会记录字符的位置(零宽度),然后选择其中一个先匹配。单个字符可能检查多次:我们看到当执行到
(d|b)
时,比较d
后发现不匹配,于是NFA引擎换表达式的另一个分支b
,同时文本位置回退,重新匹配字符'b'。这也是NFA引擎是非确定型的原因,同时带来另一个问题效率可能没有DFA引擎高。可实现反向引用等功能:因为具有回退这一步,所以可以很容易的实现反向引用、环视等一些功能!
两种引擎比较
关于这两种引擎的总结,猪哥引用《精通正则表达式》书本中的一句话来概括:
DFA(电动机) 和NFA(汽油机) 都有很长的历史,不过,正如汽油机一样,NFA 的历史更长一些。也有些系统采用了混合引擎,它们会根据任务的不同选择合适的引擎(甚至对同一表达式中的不同部分采用不同的引擎,以求得功能与速度之间的最佳平衡)。 ——《精通正则表达式》
3.回溯(重点)
作为绝大多数编程语言都选择的引擎——NFA (非确定型有穷自动机) 引擎,我们当然要再详细了解一下它的精髓——回溯。
动图中,我们可以看到当某个正则分支匹配不成功之后,文本的位置需要回退,然后换另一个分支匹配,而回退这步专业术语就叫:回溯。
回溯的原理类似我们走迷宫时走过的路设置一个标志物,如果不对则原路返回,换另一条路。
回溯机制不但需要重新计算正则表达式和文本的对应位置,也需要维护括号内的子表达式所匹配文本的状态(b匹配成功),保存到内存中以数字编号的组中,这就叫捕获组。
保存括号内的匹配结果之后,我们在后面的正则表达式中就可以使用,这就是我们所说的反向引用,在上面的案例中只有一个捕获,所以$1=b
。
回溯陷阱:讲到回溯必须提到回溯陷阱,它导致的结果就是机器CPU使用率爆满(超100%),机器就卡死了。
举个例子:text=aaaaa,pattern=/^(a*)b$/,匹配过程大致是
(a*):匹配到了文本中的aaaaa
匹配正则中的b,但是失败,因为(a*)已经把text都吃了
这时候引擎会要求(a*)吐出最后一个字符(a),但是无法匹配b
第二次是吐出倒数第二个字符(还是a),依然无法匹配
就这样引擎会要求(a*)逐个将吃进去的字符都吐出来
但是到最后都无法匹配b
这里的重点就在于 引擎会要求*
匹配的东西一点一点吐回,我们假设如果文本长度为几万,那引擎就要回溯几万次,这对机器的CPU来说简直是灾难。
有些复杂的正则表达式可能有多个部分都要回溯,那回溯次数就是指数型。如果文本长度为500,一个表达式有两部分都要回溯,那次数可能是500^2=25万次,这谁受得了!
关于更多更详细的回溯介绍,推荐大家可以阅读《精通正则表达式》这本书.
优化
编写巧妙的正则表达式不仅仅是一种技能,而且还是一种艺术。
上面我们了解到,绝大多数的编程语言都采用的是NFA引擎,而NFA引擎的特点是:功能强大、但有回溯机制所以效率慢。所以我们需要学习一些NFA引擎的一些优化技巧,以减少引擎回溯次数以及更直接的匹配到结果!
针对NFA引擎的可优化的点其实挺多的,为了方便大家记忆,猪哥也画幅结构图归纳一下,方便大家收藏细看。
在面试过程中也许会被问到关于正则的优化,大家记住几点就可以。
推荐
上面我们讲解了关于正则表达式的诞生和发展、引擎、优化等知识,但是关于正则表达式的知识点远远不止这些,所以最后猪哥推荐一些好的学习资料,大家有空可以了解学习下。
1.书
推荐正则表达式的书,那必然是《精通正则表达式》 ,目前这本书已经出了第三版,豆瓣评分8.9。
内容虽然稍有啰嗦,但是对于正则新手很友好,唯一不足是Python案例少。
2.博客
入门:菜鸟教程:https://www.runoob.com/regexp/regexp-tutorial.html
深入:某不知名大佬:https://blog.csdn.net/lxcnn
3.在线测试工具
https://regex101.com/,这个网站可以选择不同编程语言的正则支持,有语义分析、匹配测试、参考列表等,非常实用。
4.常用案例
一些简单常用的小案例汇总,菜鸟教程:http://c.runoob.com/front-end/854
最后祝愿大家都能搞定正则表达式,处理文本可以得心应手。
【end】
◆
精彩推荐
◆
推荐阅读
LSTM之父发文:2010-2020,我眼中的深度学习十年简史
作为一个部门 Leader,居然不如一个实习生
远程办公是一阵“过渡风”还是会“继续燃烧”?
2020年涨薪26-30%,能实现吗?18%数据科学家是这么期待的
NFT——加密数字资产的基石
一个学渣的 CTO 逆袭之路
你点的每个“在看”,我都认真当成了AI
相关文章:

MJExtension简介
MJExtension简介 前言:关于MJExtension更多的使用,可以到github网站上根据详述学习。 字典转模型比较流行的第三方框架 Mantle所有模型都必须继承自MTModel JSONModel所有模型都必须继承自JSONModel MJExtension不需要强制继承任何其他类 框架需要考虑的…

Discuz!常用函数解析(续)
/*** 产生随机码* param $length - 要多长* param $numberic - 数字还是字符串* return 返回字符串*/function random($length, $numeric 0) {PHP_VERSION < 4.2.0 && mt_srand((double)microtime() * 1000000);if($numeric) {$hash sprintf(%0.$length.d, mt_ran…
基于新型忆阻器的存内计算原理、研究和挑战
作者 | 林钰登、高滨、王小虎、钱鹤、吴华强来源 | 《微纳电子与智能制造》期刊引言过去半个世纪以来 ,芯片计算性能的提高主要依赖于场效应晶体管尺寸的缩小。随着特征尺寸的减小 ,器件的制备成本和制造工艺难度不断增加 ,芯 片性能的提升愈…

3、JPA一些常用的注解
常用注解有下面这些: ①:Entity、Table、Id、GeneratedValue、Column、Basic ②:Transient 用于忽略某个属性,而不对该属性进行持久化操作 ③:Temporal 一、第①组注解 Entity 标注用于实体类声明语句之前,…

实战域树部署,Active Directory系列之十九
实战子域部署<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />域树是Active Directory针对NT4的传统域模型所进行的重要改进。在NT4时代的域模型中,每个域都要使用没有层次结构的NETBIOS名称,而且域和域之…
黑科技抗疫,Python开发者大集结!
2020年初,突如其来的新型冠状病毒肺炎打乱了所有人的节奏,但社会各界迅速团结起来,为抗击疫情贡献出自己的力量。除了捐款捐物外,很多科技公司运用5G、大数据、AI、云计算等新互联网技术,以科技的手段助力抗疫…

Inplayable技术分享
Inplayable技术分享运维设计模式Web安全工具语言python运维 《aws lambda 通过codebuild上线踩坑指南之 lambda 进程被占用 status error 255》《google pay 配置sub/pub回调》《AWS攻略——使用CodeCommit托管代码》《AWS攻略——使用S3托管静态网页》《AWS攻略——使用CodeB…

将数组A中的内容和数组B中的内容进行交换(数组一样大)
#include <stdio.h>int main() {int arr1[10]{1,2,3,4,5,11,14,16,17,12};int arr2[10]{0,6,7,8,9,15,21,18,19,13};int arr3[10];int i0;for(i0;i<sizeof(arr1)/sizeof(arr1[0]);i){arr3[i]arr1[i];arr1[i]arr2[i];arr2[i]arr3[i];//不定义第三个变量的两种种方法&am…

***必备工具
***必备工具一、扫描工具 X-scan 3.1 焦点出的扫描器,国内最优秀的安全扫描软件之一!非常专业的一个扫描器! X-way 2.5 这也上一个非常不错的扫描器哦!功能非常多!使用也不难,***必备工具! SuperScan 3.0 强大的TCP 端口扫描器、Ping 和域名解析器! Namp 3.5 这个就…
通过评估假设行为来学习人类目标
来源| deepmind编译| 武明利,责编| Carol出品 | AI科技大本营(ID:rgznai100)当我们在现实世界中训练强化学习(RL)代理时,我们不会希望它们探索不安全的状态,例如将一个移动机器人开进…

ReactiveCocoa入门-part2
ReactiveCocoa是一个框架,它能让你在iOS应用中使用函数响应式编程(FRP)技术。在本系列教程的第一部分中,你学到了如何将标准的动作与事件处理逻辑替换为发送事件流的信号。你还学到了如何转换、分割和聚合这些信号。 在本系列教程…

VirtualBox虚拟机安装RedHat7.3编译Linux0.01内核
引子 由于需要编译linux0.01内核,而目前的linux版本太高需要降低gcc版本等等,需要做不少调整非常不方便。 所以,直接安装RedHat7.3,这样就好编译linux0.01的内核了。 但是,安装RedHat7.3需要注意一些问题。 下载老…
远程办公是巨头游戏?十倍扩容,他们如何做到百万级并发流量
疫情发生后,除了Zoom这样深耕视频会议多年的软件,钉钉、企业微信、飞书等一大批互联网巨头也开通了免费服务,凭借着自身庞大的资源四处招揽用户。 据说,远程办公工具是2020年的第一个风口。 疫情发生后,除了Zoom这样深…

linux下使用sort命令升序、降序、随机及组合方式排序方法
示例文件:####################################################序号 优先级 字段1 字段21 5 abc def2 5 ae3 wff6 4 l…

mysql数据库备份、恢复文档
说明:为了加强线上数据库安全,避免研发人员误操作造成数据的丢失,制作本文档。一线运维人员可以参考!一、数据备份:专用数据库备份服务器,定时对数据库进行热备、冷备,即主从设置、mysqldump冷备、mysql-bin-log日志备…

Linux环境ddd安装与使用
ddd是一个优秀的调试器,安装ddd破费周折 必须安装x开发环境 1.下载 http://ftp.gnu.org/gnu/ddd/,下载最新的ddd-3.3.12.tar.gz # wget http://ftp.gnu.org/gnu/ddd/ddd-3.3.12.tar.gz # tar zxvf ddd-3.3.12.tar.gz # cd ddd-3.3.12/ 2.配置 # ./…
华为诺亚、北大提出GhostNet,使用线性变换生成特征图,准确率超MobileNet v3 | CVPR 2020...
作者 | Kai Han, Yunhe Wang等编译 | Conv出品 | AI科技大本营(rgznai100)受限于内存空间和计算资源,将卷积神经网络部署到嵌入式设备中会比较困难。CNNs中特征图的冗余性是保证其成功的关键,但是在神经网络的结构设计中却鲜有研究…

pap和chap交叉认证
pap和chap交叉认证:R1启动pap,R2启动chap。R1上的配置:Router>enRouter#config tRouter(config)#enable s ciacoRouter(config)#line c 0Router(config-line)#pass ciacoRouter(config-line)#loginRouter(config-line)#logging syRouter(c…

如何在App中实现朋友圈功能之二快速实现用户信息的自定义——箭扣科技Arrownock...
如何在App中实现朋友圈功能之二快速实现用户信息的自定义自我关联社交元素:anSocial中很多的社交元素API,如帖子(Post)、相册(Album)、文件(File)等,这些API的可选参数中…

使用cat /proc/进程id/maps 查看进程内存映射
proc/<PID>/maps 查看进程的虚拟地址空间是如何使用的。 该文件有6列,分别为: 地址:库在进程里地址范围 权限:虚拟内存的权限,r读,w写,x,s共享,p私有; 偏移量:库在进程里地址范…
两成开发者月薪超 1.7 万、算法工程师最紧缺! | 中国开发者年度报告
整理 | 郭芮 责编 | 唐小引 出品 | CSDN(ID:CSDNnews) “求知若饥,虚心若愚”——这个原本出自《全球概览》的俳句,因为乔布斯在斯坦福大学毕业演讲中的引用而备受推崇,流传成为 IT 界的至理名言之一。在…

怎么处理404 错误页面 、处理404页面、asp.net 处理404页面
说明 On 指定启用自定义错误。如果未指定 defaultRedirect,用户将看到一般性错误。 Off 指定禁用自定义错误。这允许显示标准的详细错误。 RemoteOnly 指定仅向远程客户端显示自定义错误并且向本地主机显示 ASP.NET 错误。这是默认值。 system.web 元素 下添加下边…

转载:python原生态的输入窗口抖动+输入特效
python原生态的输入窗口抖动输入特效 出处:https://coding.net/u/acee/p/PythonPowerInput/git/blob/master/test_power_input.py __author__ Administrator import sys from lib.qm_app import App from PyQt4.QtGui import * from PyQt4.QtCore import * import …
华为提出基于进化算法和权值共享的神经网络结构搜索,CIFAR-10上仅需单卡半天 | CVPR 2020...
作者 | VincentLee来源 | 晓飞的算法工程笔记导读:为了优化进化算法在神经网络结构搜索时候选网络训练过长的问题,参考ENAS和NSGA-III,论文提出连续进化结构搜索方法(continuous evolution architecture search, CARS),最大化利用…

在.Net Micro Framework中显示汉字
摘要:MF平台支持的字体是专有格式,扩展名为tinyfnt,需要用专门的转化工具才能把windows平台上的字体转换为tinyfnt字体。在.Net Micro Framework SDK中提供了一个叫做TFConvert.exe的工具,我们可以用它在命令行下将PC机上的TrueType或者OpenT…

汇编语言使用C库函数和Linux动态链接
使用printf 代码 #cpuid2.s -- Using C labrary calls .section .data output: .asciz "The processor Vender is %s\n".section .bss .lcomm buffer, 12 .section .text .globl _start _start: movl $0, %eax cpuid …

springJDBC实现查询方法二
无废话,看代码: Overridepublic List<Sites> queryAllSites(Pager pager) {String sql "select * from sakai_site order by SITE_ID limit ?,?";Object[] obj new Object[]{pager.getStart(),pager.getLimit()};List<Sites> …

全球计算机视觉顶会CVPR 2020论文出炉:腾讯优图17篇论文入选
全球计算机视觉顶级会议CVPR2020 (IEEE Conference on Computer Vision and Pattern Recognition,即IEEE国际计算机视觉与模式识别会议) 即将于2020年6月14日-19日在美国西雅图召开。本届大会总共录取来自全球论文1470篇,腾讯优图实验室入选17篇。 作为…

gcc使用总结
1.基本选项 -o 指定输出文件名。如果不给出这个选项,gcc就给出预设的可执行文件a.out。 # cc -o XX XX.c -c 编译、汇编到目标代码,不进行链接 -v 打印较多信息,显示编译器调用的程序。 -E 仅作预处理,不进行编译、汇编…

websecurity - Web Security Testing Framework 超级牛B扫描器
Windows – Websecurify 0.3.exehttp://websecurify.googlecode.com/files/Websecurify%200.3.exeLinux – Websecurify 0.3.tgzhttp://websecurify.googlecode.com/files/Websecurify%200.3.tgzMac – Websecurify 0.3.dmghttp://websecurify.googlecode.com/files/Websecurif…