正则原理剖析

协程潮汐
• 阅读 820

一、 什么是回溯?

回溯法也称试探法,它的基本思想是:从问题的某一种状态(初始状态)出发,搜索从这种状态出发所能达到的所有“状态”,当一条路走到“尽头”的时候(不能再前进),再后退一步或若干步,从另一种可能“状态”出发,继续搜索,直到所有的“路径”(状态)都试探过。这种不断“前进”、不断“回溯”寻找解的方法,就称作“回溯法”。
假如我们的正则为 /ab{1,3}c/,其可视化形式是:
正则原理剖析

没有回溯

目标字符串是"abbbc"时,就没有所谓的“回溯”,匹配过程如下:
正则原理剖析

有回溯

如果目标字符串是"abbc",中间就有回溯。匹配过程如下:
正则原理剖析
图中第五步表示匹配失败,此时b{1,3}已经匹配到了两个b,当往第六步走的时候发现后面是个‘c’,那么此时断定b{1,3}已经匹配完成,回到之前的状态第四步,这一过程称之为回溯,这只是回溯的一种体现。

二、 JS正则原理

1、 DFA-确定有穷状态自动机-Deterministic finite automaton

特点:文本主导
DFA读入一个文本时,会记录当前表达式中所有满足匹配要求的位置,这些位置集合对应于DFA的一个状态

2、 NFA-非确定有穷状态自动机-No-deterministic finite auotmaton

特点:表达式主导
从表达式的左边开始,每次读取一个正则表达式的一个字符,检查当前文本是否匹配当前表达式,如果是则继续正则的下一个字符。

3、示例分析

正则:reg=to(nite|knight|night) 字符串:tonight
DFA匹配过程:
1、 当引擎读入文本t,记录匹配位置to(nite|knight|night)
2、 读入文本o,记录位置to(nite|knight|night)
3、 读入文本n,记录位置to(nite|knight|night) // 体现与NFA的不同之处
...
NFA匹配过程:
1、 获取表达式的to(nite|knight|night),扫描匹配字符串中的t
2、 获取表达式的to(nite|knight|night),扫描匹配字符串中的to
3、 括号中的表达式分三种情况,引擎会尝试三种情况
。。。
从示例中可以得到结论:
DFA每一次匹配会记录所有满足要求的表达式位置,组成集合,当往下面匹配时有不满足要求的集合将会被剔除,每一步都是有效的匹配,所以不存在回溯。
NFA遇到具有选择不确定性的表达式会进行试探匹配,顺着分支往下匹配,如果后续有不匹配的,那么会重新回到确定性的位置,继续下一个分支进行匹配,要回到原来的位置的前提条件就是需要记住历史状态,所以NFA具有回溯。

三、 高级功能

NFA除了支持回溯之外,还支持分组,捕获,零宽断言等高级功能,而这些功能的基础是NFA具有子表达式独立匹配的特点。

1、分组

将一个或多个字符使用括号包裹起来组成一个整体,分组分为捕获组和非捕获组。

捕获组:

示例(ABC)(ABCD(ABCDE)),存在四个分组:

内容
分组1(ABC)(ABCD(ABCDE))
分组2(ABC)
分组3(ABCD(ABCDE))
分组4(ABCDE)
捕获组的应用:
  • 反向引用
  • 计数

    注意点:
    反向引用,引用的仅仅是文本内容,而不是正则表达式。
    反向引用中为什么我们一般是使用的分组是从\1开始的?
    非捕获组:

    以 (? 开始的组就是非捕获组,不将匹配到的字符存储到内存中,从而节省内存。
    (?:a|A)123(?:b)可以匹配a123b或者A123b 

    非捕获组有很多种形式,其中包含零宽断言、模式修正符等。环视又称环视或预搜索
    零宽断言,常见的零宽断言有四种:
    a) (?=exp):零宽正向先行断言
    let reg = /(test)(?=suffix)/ // 匹配后面为suffix的test

    b) (?<=exp):零宽正向后行断言
    let reg = /(?<=prefix)(test)/ //匹配前面为prefix的test

    c) (?!exp):零宽负向先行断言
    let reg = /(test)(?!suffix)/ // 匹配后面不是suffix的test

    d) (?<!exp):零宽负向后行断言
    let reg = /(?<!prefix)(test)/ // 匹配前面不是prefix的test

    零宽是何意?

    零宽断言是一种零宽度的匹配,它匹配到的内容不会保存到匹配的结果中去,最终匹配的只是一个位置,这个位置的结果代表是否。

    2、模式修正符:

    一般情况下我们会在表达式的后面加上g,i,m,s对整个表达式进行修饰,js正则表达式还支持对局部表达式进行修饰的用法。
    (?i)AB 对表达式(?i)后面的字符开启不区分大小写的限制,可以匹配:ab、aB、Ab、AB
    (?i:a)b 只对a不区分大小写,可以匹配:Ab、ab

    3、捕获

    ES6正则命名捕获,不需要纠结分组的下标,根据定义正则表达式对分组的名称进行访问。
    示例:
    let str = '2021-09-26'
    let reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
    let ret = str.match(reg).groups
    输出结果:{year: '2021', month: '09', day: '26'}

四、 实战分析

Input.Password密码输入组件,密码的规则是满足四种字符中的至少三种字符类型,如下图:
正则原理剖析
将表达式中的\W替换为“()!@#$%^&*|?><”即可
new RegExp("^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z\W]+$)(?![a-z0-9]+$)(?![a-z\W]+$)(?![0-9\W]+$)[a-zA-Z0-9\W]{8,}$");

点赞
收藏
评论区
推荐文章
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
面向状态机编程:复杂业务逻辑应对之道
在研发项目中,经常能遇到复杂的状态流转类的业务场景,比如游戏编程中NPC的跳跃、前进、转向等状态变化,电商领域订单的状态变化等。这类情况其实可以有一种优雅的实现方法:状态机。
Stella981 Stella981
3年前
DirectX3D设备丢失(lost device)的处理(二)
一个Microsoft?Direct3D?可以处于操作状态或丢失状态。操作状态是设备的正常状态,设备按预期运行并present所有渲染结果。当事件发生时,如全屏应用程序失去键盘输入焦点,设备就转变到丢失状态,这会导致渲染无法进行。丢失状态表现为所有渲染操作的悄然失败,这意味着即使渲染操作失败所有的渲染方法仍可以返回成功码。在这种情况下,IDirect3DD
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql操作中卡死 解决方法
1.使用指令查询当前进程showfullprocesslist;查询全部当前进程;showprocesslist;只列出前100条2.找出卡死的进程id3.删除卡死进程kill99;99为卡死id4.其他状态含义showstatus;Ab
Stella981 Stella981
3年前
Netty学习笔记1:5种IO模型
1阻塞IO模型从字面来理解,就是调用时可能被阻塞,什么叫阻塞,要知道一个进程有N种状态,学过OS都知道如果阻塞,就会把当前进程放在某个条件的阻塞队列里。直到条件满足了,才会转移此进程进入就绪队列。当然,就绪队列还有个优先级的概念,就不扯远了。阻塞IO.1)调用API,比如 r
贾蔷 贾蔷
2个月前
【2023 CSP-S密码锁(洛谷P9752)】题解:动态规划与集合交集的巧妙应用
一、题目解读2023年CSPS的“密码锁”题目(洛谷P9752)要求破解一种环形密码锁机制。题目给定n组状态,每个状态由5个数字组成,通过“单拨圈”或“双相邻拨圈”操作可改变数字。正确密码需满足:通过操作能从初始状态转换到所有给定状态,且给定状态本身不能作
十月飞翔 十月飞翔
3年前
Centos7 防火墙
查看防火墙的状态的命令为:sudosystemctlstatusfirewalld。打开防火墙的方式有两种,一种是打开后重启会恢复回原来的状态,命令为:sudosystemctlstartfirewalld;另一种是打开后重启不会恢复到原来的状态,命令为:sudosystemctlenablefirewalld,这种方式输入命令后要重启系统
3A网络 3A网络
2年前
一文读懂浏览器存储与缓存机制
一文读懂浏览器存储与缓存机制浏览器存储CookieCookie是HTTP协议的一种无状态协议。当请求服务器时,HTTP请求都需要携带Cookie,用来验证用户身份。Cookie由服务端生成,存储在客户端,用来维持状态。通常Cookie由以下值构成:名称(name)值(value)域(Domain)值(value)路径(Path)
贾蔷 贾蔷
2个月前
2013 蓝桥杯 省赛B组 翻硬币(洛谷P8597题) 从暴力BFS到贪心算法的优化之路
一、问题背景与理解洛谷P8597是一道经典的翻硬币问题,题目描述如下:给定两个由''和'o'组成的字符串s1和s2,分别表示初始状态和目标状态。每次操作可以选择任意位置开始翻转连续的k个硬币(''变'o','o'变'')。要求计算出从初始状态变为目标状态所