今天我们来讲一下正则
零宽断言还有其他的名称,例如"环视"或者"预搜索","预查" 等等
作用:
作用是给指定位置添加一个限定条件,用来规定此位置之前或者之后的字符必须满足限定条件才能使正则中的字表达式匹配成功
- (?=exp)
也叫 零宽度正预测先行断言,它断言此位置的后面能匹配表达式exp - (?<=exp)
也叫 零宽度正回顾后发断言,它断言此位置的前面能匹配表达式exp - (?!exp)
也叫 零宽度负预测先行断言,断言此位置的后面不能匹配表达式exp - (?<!exp)
也叫 零宽度负回顾后发断言来断言此位置的前面不能匹配表达式exp
归类:
不太好记,那么归一下类
概念 | 功能 |
---|---|
预测/先行 | (模式在前),要求后面的符合匹配 |
回顾/后发 | (模式在后),要求前面的符合匹配 |
正 | 符合匹配 |
负 | 不符合匹配 |
为什么要用括号括起来?继续看
零宽度 断言,我们理解一下:
零宽度: 就是不占据字符宽度, 不匹配任何东西,只是一种模式 (那到底什么意思?等会儿再说)
断言:就是布尔表达式, 单元测试中我们经常使用断言,比如 asset(xxx, true) 这种表达式,用来判断我们的结果是否正确
首先我们来看 正预测先行断言:
对于一个字符串,我们要求它以 特定 字符串 开头:
可以看到,模式在前,但是没有匹配任何字符,不占据宽度,只是告诉后面的要跟什么字符串。
不然 (?=hello)helloxxxx 是什么鬼? 这里模式是不占据宽度的(零宽度)!
写法和分组有点类似,但是分组是占据宽度的
同时,我们发现,要 匹配 hello 开头的字符串,我们得这么写:
- (?=hello)hello
- (?=hello)\w{5}
有没有感觉写法有点多余? 可以转变下思路,使用 正回顾后发断言:
这样一看,好像没有多余的东西了,太棒了!
但是,正回顾后发断言,如果按照前面所说,应该是这样的:
同样的问题,感觉有点多余
那么,前一个的不多余的写法该如何理解?
不就是把 hello, \w{5} 省略了吗?
我们只是告诉要以什么字符串开头,而不必要再用 hello, \w{5} 明确匹配开头的字符串。
前面说:对于正回顾后发断言,是 (模式在后)要求前面的符合匹配。但是这里的形式,看上去是 模式在前,是由于我们把前面的省略了。
那么,理解了上面说的,对于其它 3 种是一样的道理,只不过就是顺序和要求匹配不匹配的问题了。
理解了原理,下面来实战几道题:
案例一:
可以用 /a(?=b)c/ 匹配 'abc' 吗?
注意: (?=b) 是不占据宽度的
案例二:
对于:str = "hello &test1;test&qout;";
匹配&和;之间不含有test的字符
注意 exec 和 match 是不同的
案例三:
对于: str = "<div id='1'><img class='xx'></div><div id='1'><input type=''text"></div>";
匹配不含有<img>标签的<div></div>标签
答案: 正则表达式:/<div[^>]*>((?!<img[^>]*>).)+</div>/g
案例四:
/^(?=^.{8,}$)(?=.*\d)(?=.*\W+)(?=.*[A-Z])(?=.*[a-z])(?!.*\n).*$/
上述表达式的功能 ?
分析:
这个看起来比较复杂。不过,分解开来其实一点也不复杂,这是由五个零宽断言和一个负向零宽断言(负向表否定)组成。
前五个分别是:必须是8位以上、必须出现数字、必须出现特殊符号(非字母数字下划数)、必须出现大写字母、必须出现小写字母。最后一个负向零宽断言是:不得出现换行。
大家会发现每个断言都是以 .* 开头,那这个表示什么意思呢?因为这些断言都是写在同一位置,而同一位置是不可能同时出现以上六种情况的。所以用 .* 来告诉表达式,这个断言之前可以有字符(意即这个断言可以出现在接下来的字符串任何位置)
所以,可以用来做强密码验证
网友评论