摘要:先看一张来自于菜鸟教程的定义四种形式,加和不加有什么区别,区别就是捕获元与非捕获元,表现形式就是用方法去匹配,捕获组会单纯保存在一组变量中。捕获元与非捕获元搞懂了,那与啥区别呢,答案,两个区别。
想读懂世间所有的那些{{BANNED}}正则表达式?做梦,年纪轻轻,想啥呢,尽自己最大努力学就行
引子JS学了用了也快一两年了,对象啥的找到了也会用了,继承啥的也入门了,但看别人的框架代码,总是会随时卡壳,有一个重大的原因,就是那看不懂的一串串火星文字(正则表达式),学习吗,就是查缺补漏,不怕你不懂,就怕你觉得自己全懂了。说正事之前,先推荐一款软件:RegexBuddy,无论是做正则的测试还是过程的研究,都是一款利器。
知识汇总语法复习,重点三块知识:
贪婪匹配(? 0=
特殊字符:^ $ . * + ? = ! : | / ( ) [ ] { }
,火星文,基本就是他们组成的,要想匹配字符的本意,字面量表达式在特殊字符前加单斜杠,用new声明的需要加双斜杠;
非捕获元字符:?:,?=(正向预查),?!(负向预查);
回溯引用,前面的字符匹配基本都和他有关;
其他,什么字符边界啊,括号啊,中括号啊,等等 ;
正则表达式解析原理:这个不算我等渣暂时能写出来的,推荐一篇
层层递进剖析 贪婪匹配先理解贪婪匹配,正则表达式的日常应用基本也就满足了,在菜鸟教程的语法开篇就已经提的很详细了,比如有一个regex:/Chapter[1-9]/,这个字符串我们只能匹配到Chapter1-Chapter9,也就是Chapter的一级标题,但我们想匹配到二级或者三级标题怎么办,这里就用到了贪婪匹配,就是在目标字符串中最大化的匹配结果,将前面的regex:/Chapter[1-9]/改成/Chapter[1-9]+/,这样我们就能匹配Chapter1,Chapter12,Chapter123,但如果我们将其改为/Chapter[1-9]?/,这个无论/Chapter后面输入多少个数字,都只能最多匹配一个数字,这里就是Chapter1,但与最初的表达式不同的是,这个表达式也能匹配裸的Chapter,这就是所谓(X?),问号前面的X可出现0次或者1次,当我们将其改为/Chapter[1-9]星号(避开markdown语法)/,这个最后可以达到?和+共同的结果,也就是所谓的,x出现任意次数。上面这些我们也可以通过[n,m]即n= 与贪婪匹配成对的另一个叫懒惰匹配,在前面出现的所有贪婪匹配后面加上一个?,这样整个表达式就成了懒惰匹配,可以理解为最小化匹配,比如/Chapter[1-9]+/匹配Chapter12345的结果是Chapter12345,但/Chapter[1-9]+?/匹配的结果就是Chapter1;/Chapter[1-9]{2,4}/匹配结过是Chapter1234,而/Chapter[1-9]{2,4}?/结过是Chapter1234,这就是所谓的最小化去匹配结果,取下限,通常称为懒惰模式。 以前看到什么?:,?=,?!,用的少,也就没留意,最近大面积灾荒,经常看到,甚是恐惧,以至于前面在读gulp里面碰见个regex表达式:/-[0-9a-f]{8,10}-?/(匹配app-7ef5d9ee29.css这一类表达式中的md5值),就一头栽进去,"-?"到底又有什么特殊的含义,最后才发现,那TMD就是一个贪婪匹配,你个蠢货,但确实搞不懂源码作者在想啥,也许是我没碰到app-7ef5d9ee29-any.css这样的文件名,要不非得多加个"-?"干啥,让我直往坑里跳。 从上面代码运行的截图可以看出区别一,也就是(?:pattern)的形式的捕获元匹配的结果会保存在最终的结果中,而(?=pattern);区别二看的不是很明显,这时我们需要依靠RegexBuddy,这个过程中到底发生了什么?看运行截图,如果你够仔细,你可以发现区别,第一次匹配到结果,开始第二次匹配时,?:是从字符索引3开始,而?=是从2开始,这就是前面所说的消耗字符与不消耗字符。
回到正题,先搞懂什么叫捕获组,概括起来就是,用括号如‘(pattern)’这样的形式,匹配满足括号中的,就是一个捕获组。先看一张来自于菜鸟教程的定义:
四种形式,加?和不加有什么区别,区别就是捕获元与非捕获元,表现形式就是用exec方法去匹配,捕获组会单纯保存在一组变量中。理论太枯燥,直接看例子,来源于JS高设page106,略有改动: var str ="mom and dad and baby";
var pattern = /mom( and dad( and baby))/; //捕获元形式
var pat= /mom(?: and dad(?: and baby))/; //非捕获元形式
var mat = pattern.exec(str);
var match = pat.exec(str);
console.log(mat);
console.log(match);
看着devtools打印的结果,是不是有点眉目,是的,匹配的结果虽一致,但捕获组匹配时,将满足捕获元形式的单元多带带保存为一个匹配结果,而非捕获元不多带带保存,只保存完整匹配结果。我们常见的Regexp.$1,$2其实就是对捕获组结果的引用。
捕获元与非捕获元搞懂了,那(?:pattern)与(?=pattern)啥区别呢,答案,两个区别。区别一:前者匹配的结果包含捕获元,后者匹配的结果则不包含;区别二:前者匹配捕获元时,消耗字符(索引),而后者不消耗。还是来看一个例子:var str ="ababa";
var pattern = /ab(?:a)/g;
var pat= /ab(?=a)/g;
var mat = pattern.exec(str);
var match = pat.exec(str);
console.log(mat);
console.log(match);
mat = pattern.exec(str); //全局模式,第二次匹配
match = pat.exec(str); //全局模式,第二次匹配
console.log(mat);
console.log(match);
好了,最后一个问题,整箱预查(?=pattern)与负向预查(?!pattern),其实从中文单纯来理解负向预查,是会带来歧义的。这里的负向其实单单就是正向预查的取反,即要匹配的字符不满足捕获的条件,才能匹配到结果。
如果文章有什么描述不正确或模糊的地方,还请及时指正。
好了,先就说这么多嘛,虽然是无业游民,那也应该有享受周末的权利吧,毕竟找工作的压力那么大,还是要自我缓解一下,see you last week。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/84674.html
摘要:则是将作为一组,表示出现多次。如果没有使用标示,则仅返回第一个完整匹配及其相关的捕获组。构造函数的全局属性到存储了分组匹配的结果。 showImg(https://segmentfault.com/img/remote/1460000018749261?w=1362&h=781); 感谢 本文参考《正则表达式迷你书》 分组和分支结构 分组 括号可以提供分组的功能。/a+/, 标示a出现...
摘要:正则表达式语法字符与字符类特殊字符以上特殊字符要想使用字面值,必须使用进行转义字符类包含在中的一个或者多个字符被称为字符类,字符类在匹配时如果没有指定量词则只会匹配其中的一个。 1. 正则表达式语法 1.1 字符与字符类 1 特殊字符:.^$?+*{}| 以上特殊字符要想使用字面值,必须使用进行转义 2 字符类 1. 包含在[]中的一个或者多个字符被称为字符类,字符类在匹配时如果没有指...
摘要:对于含有量词正则表达式,量词是贪婪模式,会优先选择尽可能多的匹配修饰的字符,所以该表达式会优先选择匹配一个字符,当匹配不到时再选择不匹配字符。 正则表达式的语法 普通字符 字母、数字、汉字、下划线以及一些没有特殊定义的标点符号,都属于普通字符,正则表达式中的普通字符匹配字符本身,如: var str = abced console.log(str.match(/a/)) // [a,...
摘要:非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。 导读 你有没有在搜索文本的时候绞尽脑汁, 试了一个又一个表达式, 还是不行. 你有没有在表单验证的时候, 只是做做样子(只要不为空就好), 然后烧香拜佛, 虔诚祈祷, 千万不要出错. 你有没有在使用sed 和 grep 命令的时候, 感觉莫名其妙, 明明应该支持的元字符, 却就是匹配不到. 甚至,...
阅读 936·2021-11-22 09:34
阅读 2147·2021-11-11 16:54
阅读 2176·2021-09-27 14:00
阅读 922·2019-08-30 15:55
阅读 1509·2019-08-29 12:46
阅读 580·2019-08-26 18:42
阅读 615·2019-08-26 13:31
阅读 3166·2019-08-26 11:52