0
点赞
收藏
分享

微信扫一扫

讲透正则表达式及其底层实现

云岭逸人 2022-04-14 阅读 84

正则表达式语法:

.匹配任意字符

-指定范围,如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>|

简单的例子:

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,然后就会拿string的第二个B和C比较,发现不匹配,就会回溯,然后再拿B{1,3}和string的第二个字符作比较

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

string="ABBC"

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

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

优化字符匹配效率:

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

举报

相关推荐

0 条评论