正则表达式
正则表达式(英语:regular expression,常简写为regex、regexp或RE),又称规律表达式、正则表示式、正则表示法、规则表达式、常规表示法,是计算机科学概念,用简单字符串来描述、匹配文中全部匹配指定格式的字符串,现在很多文本编辑器都支持用正则表达式搜索、取代匹配指定格式的字符串。
--摘录自维基百科
总而言之,言而总之,正则表达式就是通过特定的字符来匹配特定的文本
零宽断言
简介
零宽断言: 简单来说就是用来判断一个规则之前或者之后的规则是否满足或者不满足
说起来有点迷糊对吧,举个例子就知道了:
这里有一个文本 "apple apple apple
" ,可以看到有三个 ”apple“,并且中间用空格隔开,那现在我有个需求,我要匹配到中间 "apple",应该怎么做:
Tips: 本文使用的正则表达式测试网站是 https://regexr-cn.com/
/\sapple\s/
可以看到,虽然我们拿到了中间的 ”apple“,但是同时还顺带了旁边的空格,但我只想要 “apple” 怎么办,这时候就需要零宽断言来解决。
思考
但我们先不急着讲零宽断言,因为他的理论比较难懂,先来思考一下,如果是你,你的大脑会这么得到中间的 “apple”。首先中间的 “apple” 有什么特点,是不是左右两边都有空格?没错,这个空格就是关键,那么我们想要匹配到中间的 “apple”,是不是需要满足以下条件:
- 先有一个空格
- 再看接下来是不是 apple
- 最后看接下来是不是空格
那么可以随手写出来以下正则 /\sapple\s/
,但是这不是和第一次写的一样吗,没错,这时候我们想想,两边的空格我们并不需要显示在结果中,但是我们需要匹配它,两边的空格仅仅是给我们作判断,所以我们来优化一下之前的步骤:
- 判断是否有空格
- 匹配apple
- 判断是否有空格
这里的 “判断”,我们换个词也可以说是 “断定”,那么我们就说这个不需要显示在结果中,但是我们需要匹配它的正则表达式是 “断言”,但我们又发现,我们不希望把断言匹配到的任何字符放到最终的结果中,它仅仅是做一个判断,所以它并不会改变任何字符,因此可以抽象的理解为,断言的 宽度为0,因此得名:零宽断言。
概念引入
零宽断言:
用于查找在某些内容之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。
--百度百科
仔细阅读上面的概念,有了之前的铺垫,应该就能很好理解 零宽断言 了。
再拿之前的案例来说,两边的空格就是断言,也就是说,在一个特定位置 “apple”,要同时判断左边的断言和右边的断言,我们称左边的断言是 “后发断言“,因为 ”apple“ 作为特定位置,它相对于左边的断言是在右边的,听起来可能有点绕,画个图就理解了。
那么左边的我们已经知道了是 “后发断言”,相反,右边的就是 先发断言?哈哈,这名字是不是怪怪的,其实他也有个专属的名字叫 “先行断言”。
但是,有没有发现我们现在的断言都是默认了符合要求的情况,事实上还有不符合要求的情况,那就是 在特定位置的前面或者后面的断言不符合时,则成功匹配。我们称这种行为是负向。
相反,在特定位置的前面或者后面的断言符合时,则成功匹配,我们称这种行为是正向
零宽断言的4种分类
Tip: 在网上你可能会看到各种各样的叫法,但是意思都一样,以下写的 “全称” 是规范完整的叫法
正向先行断言
全称:零宽度正预测先行断言
定义:当断言是真的,且判断当前位置(如之前说的apple)后面的字符是否符合某个模式(即断言)
语法:(?=exp) --> 其中exp为正则表达式
案例:一份学生名单,要求仅匹配出姓名为XiaoMing,且学号为2号的学生
XiaoMing 1
XiaoMing 2
LiHua 3
答案:
/XiaoMing(?=\s\s2)/
正向后发断言
全称:零宽度正回顾后发断言
定义:当断言是真的,且判断当前位置,前面的字符是否符合某个模式
语法:(?<=exp) --> 其中exp为正则表达式
案例:在以下菜谱中匹配出周三吃的所有菜
周一: 鱼香肉丝,番茄蛋汤
周二: 红烧鱼,猪肉汤
周三: 红烧鱼,番茄炒蛋
周四: 猪脚饭,红烧小排骨
周五: 骨肉相连,骨头汤
答案:
/(?<=周三..).+/
负向先行断言
全称:零宽度负预测先行断言
定义:当断言是假的,且判断当前位置,后面的字符是否符合某个模式
语法:(?!exp) --> 其中exp为正则表达式
案例:找出所有不是163邮箱的地址,要求返回完整邮箱地址
XiaoMing@163.com
XiaoAi@qq.com
LiHua@163.com
LiBai@126.com
答案:
/.+@(?!163\.com).+/g
负向后发断言(不常用)
全称:零宽度负回顾后发断言
定义:当断言是假的,且判断当前位置,前面的字符是否符合某个模式
语法:(?<!exp) --> 其中exp为正则表达式
案例:用负向后发断言匹配第一个 “apple”
apple apple apple
答案:
/(?<!\s)apple/
回顾开头
现在再来看文章最开始举的例子,是不是能很轻松拿捏了:有一段文本 "apple apple apple
",中间用空格隔开,匹配出中间的 “apple”。
答案:
/(?<=\s)apple(?=\s)/