正则表达式的用法及原理

2022-08-18 15:09:26 浏览数 (1)

由于工作中和正则表达式打交道比较多,所以花了几天的时间系统学习了正则,在此总结一下。

正则表达式:是一种非常强大的文本处理工具

主要用途:

1.校验数据的有效性(验证手机号、邮箱、身份证号等)

2.用于查询或者匹配符合的文本内容(语音助手query正则召回、egrep查询日志等)

3.对文本进行切割、替换等操作

基本语法:

三种匹配模式:贪婪匹配、非贪婪匹配、独占匹配

1.贪婪匹配:表示次数的量词默认是贪婪的,在贪婪模式下,会竟可能最大长度的去匹配

对于text = 'aaabb'

regex = 'a ' 匹配结果:'aaa'

regex = 'a*' 匹配结果:'aaa','','',''

按照text下标从0开始,试着分析下:

代码语言:javascript复制
i. [0-3] 匹配'aaa' 到b的时候不满足
ii. [3,3]匹配剩下的'bb',匹配不了,返回空串
iii. [4,4]匹配剩下的'b',匹配不了,返回空串
iv. [5,5]匹配剩下的空串,返回空串

2.非贪婪匹配:在量词后面加上问号(?),就变成非贪婪匹配

这个regex本意都是查找被""括起来的内容,第一张图只有量词 这种情况下就是贪婪匹配,匹配了整个字符串;第二张图在量词 后添加了?这样就变成了非贪婪匹配,匹配了两个字符串

3.独占模式:贪婪模式和非贪婪模式都需要回溯,在有些场景下不需回溯,匹配不上就返回失败,给量词后面加上 ,就可以变成独占匹配

regex = 'xy{1,3}z'

text = 'xyyz'

i. 贪婪匹配:y{1,3}最大长度的匹配y,直到去匹配text中的z失败后,吐出text中的z(回溯),然后再用正则中的z去匹配text中的z

ii. 非贪婪匹配:=> regex = 'xy{1,3}?z',y{1,3}? 最小长度的匹配y,匹配了xy之后,用正则中的z去匹配字符串中的z不匹配,正则回溯到y{1,3}?继续来匹配y,匹配成功

iii. 独占匹配:=> regex = 'xy{1,3} yz',如图就只匹配一个text,不回溯

分组与引用

一般来说我们会把以()括起来的看做一个整体,也即分组的概念

代码语言:javascript复制
比如:2022-06-29 21:29:30
写一个简单的正则来匹配的话:regex = (d{4}-d{2}-d{2}) (d{2}:d{2}:d{2}
该正则并不严谨,只是为了说明,这里第几个左括号就表示第几个分组(即第几个分组编号),默认下根据圆括号分完组的子组会保存,方便被后面进行引用

引用的语法: '分组编号' , 如regex = '(w ) 1' 能够匹配连续两个相同的word,1即分组引用的语法

另:如果不想保存子组的话,可以使用(?:regex表达式)来不保存子组

多分支选择时,左边优先

regex = '北京|北京市',text = '北京市' 如下图并不匹配,因此要想匹配北京市可以regex = '北京市|北京' 或者是把公共部分提取出来 regex = 北京市?

常见的4中匹配模式

正则中的断言:对匹配到的文本有位置要求,以下图为例:想要匹配11为数字的手机号,但是我输入14位数字的话,前11位是可以匹配的

1.单词边界(word boundary)

eg: regex = 'tom'

text = 'tom will go hiking tomorrow'

其实是匹配了两次, 第一次是tom,第二次是tomorrow的前半部分

语法:b

代码语言:javascript复制
regex = 'tom' 包含tom的word
regex = 'btom' 以tom开头的word
regex = 'tomb' 以tom结尾的word
regex = 'btomb' 只匹配tom

如果要准确匹配某个word的话,就可以使用(bw b)

2.行的开始和结束 ^$

3.环视(look around) 要求匹配部分的前面或者后面要满足/不满足某种规则

注:环视虽然有括号,但是不会保存为子组(只表示对文本左右环境的要求,只匹配位置,并不关心其他)

正则相关历史,两个流派

正则匹配原理

正则能够处理复杂文本由于有穷状态自动机(finite automanton).

自动机是指系统可以根据相应的条件,在不同的状态下进行转移(1个系统有有穷个状态,不同状态代表不同的含义,每次的操作如输入字符串,可能会使状态转移)

有穷自动机分为DFA(determinstic finite automanton)和NFA(non-determinstic finite automanton)

代码语言:javascript复制
NFA工作机制:先看正则后看文本
regex = 'xiao(ai|mi|du|ma)'
text = 'i work at xiaomi'
从正则表达式的第一个字符x,在text文本中查找x,匹配后直到走到字符o,接着用第一个分支ai中的a去匹配text文本中的m,匹配失败,第一个分支ai结束,用第二个分支mi的第一个字符m继续和text文本匹配,最终匹配成功,那么剩下的第三、四个分支就不用继续匹配了,类似于Java中&&的短路逻辑
DFA工作机制:先看文本后看正则
regex = 'xiao(ai|mi|du|ma)'
text = 'i work at xiaomi'
从text文本的第一个字符i开始去匹配regex的第一个字符x,不匹配,继续向后走,直到匹配完xiao,在匹配多分支结构时为并行的匹配,同时去用text文本中的字符m分别匹配a,m,d,匹配不上的该分支就结束,最终就分支mi胜出,匹配成功

未完待续......

0 人点赞