深入正则表达式及其底层原理及优化(自动机的三种匹配模式)

正则表达式语法:

.匹配任意字符

-指定范围,如1-9代表1到9之间的所有数字

*代表匹配零次或多次之前的段落 AB*表示A,AB,ABB,ABBB等

+代表匹配多次之前的段落 AB+表示AB,ABB,ABBB等

?代表之前的字符可有可无 AB?表示A,AB

|表示或者,("A"|"B")表示字符A或字符B

^a只能匹配以小写字母为行首的行: "a..."

a$ 只能匹配以小写字母为行尾的行: "...a"

^a$只能匹配a

()为括号内的为一组,优先运算

[] 为字符集合,[ABc]匹配的字符为ABc,括号中的^代表否定,[^ABC]代表除了ABC之外的所有字符

{} 指出一个模式可能出现的次数,{1,5}代表前面段落出现为1到5次

\s为空白符,\S为非空白符,则[\s\S]代表所有字符

\w匹配字母、数字、下划线

\d匹配所有数字单个字符,\D匹配所有非数字单个字符

\b:表示字母数字与非字母数字的边界, 非字母数字与字母数字的边界。

\B:表示字母数字与(非非)字母数字的边界,非字母数字与非字母数字的边界。

另外如果文本中有正则表达式的关键字,那么加\表示转义,那么\\代表斜杠本身,\.代表需要匹配文本中的.

[\u4e00-\u9fa5]为中文字符匹配

运算优先级:

从高到低:

转义符>圆括号和方括号>限定符>定位点和序列(即:位置和顺序)>或

\>(), (?:), (?=), []>*, +, ?, {n}, {n,}, {n,m}>^, $, \char>|

零宽断言:

 两个正则表达式提取出想要的内容完全可以用零宽断言处理

(?=exp) 零宽度正预测先行断言,后面为exp才匹配,但是不算在捕获组中

(?<=exp) 零宽度正回顾后发断言,前面为exp才匹配,但是不算在捕获组中

(?!exp) 零宽度负预测先行断言,前面不为exp才匹配,但是不算在捕获组中

(?<!exp) 零宽度负回顾后发断言,后面不为exp才匹配,但是不算在捕获组中

举几个栗子:

零宽度正预测先行断言

123hello
456hello
789hello

如何只匹配前面是456的hello匹配呢

(?<=456)hello

零宽度正回顾后发断言

123hello
456hello
789hello

如何只匹配前面不是456的hello匹配呢

(?<!456)hello

零宽度负预测先行断言

hello123
hello456
hello789

如何只匹配后面是456的hello匹配呢

hello(?=456)

零宽度负回顾后发断言

hello123
hello456
hello789

如何只匹配后面不是456的hello匹配呢

hello(?!456)

简单的例子:

IP地址正则表达式:

^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$

首先IP地址的区间为0.0.0.0~255.255.255.255

250-255 有 25[0-5]

200-249 有 2[0-4]\d

0-200 有 [01]?\d\d?

0-255就有(25[0-5]|2[0-4]\d|[01]?\d\d?)

.在正则表达式中有含义,那加上\则表示原来的字符

前三个末尾带“.”,重复三次就有((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}

再带上末尾的就有((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)

加上前后定位符即可以判断是否这段字符串为正则表达式

^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$

底层原理:

自动机有三种匹配模式:贪婪模式、懒惰模式、独占模式

常用的NFA自动机,该自动机具有贪婪特性,会尽可能匹配多的字符

举个简单的例子:

string="Today is a nice day."

regex="day"

首先拿d和T匹配发现不成立,再拿d和o作比较也不匹配,往后,d匹配,再看第二个字符a符合,如此找到匹配项目day

大概原理就是这样,实际上会做很多优化,但是其原理不变

回溯会花费CPU资源

贪婪模式:

string="ABBC"

regex="AB{1,3}C"

正则表达式中的B{1,3}会匹配string的前两个BB,也会比较第三个C,然后发现不同,就会回溯,最后开始C的匹配,匹配成功

当B{1,3}后面加了“?”,以后就会变成懒惰模式:

string="ABBC"

regex="AB{1,3}?C"

正则表达式中的B{1,3}会匹配string的第一个B,然后就会拿regex的C和string的第二个B比较,发现不匹配,就会回溯,然后再拿B{1,3}再和string的第二个B和第三个B做比较,最后匹配成功

当在B{1,3}之后加多一个 + 符号,那么原先的贪婪模式就会变成独占模式,就不会发生回溯了

string="ABBC"

regex="AB{1,3}+BC"

B{1,3}把两个B全占据了,结果string中的C和regex的BC做匹配结果发现无法匹配

优化字符匹配效率:

当用户输入的字符串过大的时候,会产生大量回溯,在保证正确的情况下可以将其转换为独占模式,可大量减少回溯,减少CPU消耗率

下面是正则表达式在C++中的调用:

  C++下的正则表达式入门_星空_AZ的博客-CSDN博客

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值