特意写了一篇文章记录了一下:
https://www.cnblogs.com/xiangyuecn/p/10668378.html
提取<abcdef>\n<abczzz>
中首个不包含 def 结尾的 abc 标签,只知道def
,不知道zzz
。
很简单能写成( v2 页面浏览器控制台测试,但 not only javascript ):
/<abc(?!def).+>/.exec("<abcdef>\n<abczzz>")
但往往我们不能写死abc
,顺理成章的就写成了:
/<.+(?!def).+>/.exec("<abcdef>\n<abczzz>")
上面这个不生效,昨天刚发现写成这样就可以了:
/<(?:.(?!def))+>/.exec("<abcdef>\n<abczzz>")
.+(?!def)
不会生效,前瞻不会和前面的+、*、{}
起作用吗?由于/<.+(?!def).+>/
结尾还有一个贪婪匹配(虽然实际上只会匹配到结尾仅仅一个字符,看上去像是会匹配所有字符一样,不测试好难看出是哪个.+匹配出来的),这个例子不太好。
换成#1楼这个例子吧,没这么多干扰:
/<.+(?!def)zzz>/.exec("<abcdefzzz>\n<abczzz>")
另注:这里所写的语法,js应该都支持的吧。
1
xiangyuecn OP 又发现另一种有效写法:
/<(?!.+def).+>/.exec("<abcdefzzz>\n<abczzz>") 可能是结尾的.+导致的不能匹配,但这样写还是不行: /<.+(?!def)zzz>/.exec("<abcdefzzz>\n<abczzz>") |
2
frank611 2019-04-08 08:26:55 +08:00 via Android
def 后面的.+是不对的,+是必须匹配一个字符或者更多
|
3
binux 2019-04-08 08:27:32 +08:00
/<(.+)(?!def)(.+)>/.exec("<abcdef>\n<abczzz>")
你就知道为什么了 |
4
xiangyuecn OP @binux 还是不明白,第一个分组捕获到 abcde,预期想要是 abc,前瞻不会和前面的+、*、{}起作用吗?
|
5
binux 2019-04-08 08:36:41 +08:00 1
@xiangyuecn #4 别整那么多名词,Matches 'x' only if 'x' is not followed by 'y',你自己看看"第一个分组捕获到 abcde"还 followed by 'y' 了吗
|
6
zhyl 2019-04-08 08:36:53 +08:00 via Android 1
.+ 贪婪匹配
|
7
labnotok 2019-04-08 09:23:20 +08:00 via Android
貌似 js 不支持预查吧,只能手动分组
|
8
xiangyuecn OP @binux 还是不太明白,第一个分组的确是捕获到了`abcde`呀,
照着你的思路找到 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions 的解释中有个例子: > >>>>> Matches 'x' only if 'x' is not followed by 'y'. This is called a negated lookahead. For example, /\d+(?!\.)/ matches a number only if it is not followed by a decimal point. The regular expression /\d+(?!\.)/.exec("3.141") matches '141' but not '3.141'. > >>>>> 发现一个现象: 符合预期:/(\d+)(?!\.1)/.exec("123.141") 符合预期:/([^.]+)(?!\.1)/.exec("123.141") 无效:/(.+)(?!\.1)/.exec("123.141") 难以理解,最后一个就是我的写法,咳。。。 |
9
araraloren 2019-04-08 09:29:27 +08:00
js 的正则有些特性不支持: https://www.regular-expressions.info/javascript.html
|
10
xiangyuecn OP |
11
noqwerty 2019-04-08 09:37:16 +08:00 1
你这个非要用正则的话感觉只能 <(?!.+def>).+> ,你的写法里 <.+(?!def).+> 第一个.+是贪婪的,会把 def 也包括进去。
|
12
noqwerty 2019-04-08 09:38:06 +08:00
另外测试正则的时候 https://regex101.com/ 很好用
|
13
binux 2019-04-08 09:38:16 +08:00 1
@xiangyuecn #8
/<.+(?!def).+>/.exec("<abcdef>\n<abczzz>") 第一个 .+ 匹配到了 abcde,之后是 f,不是 def,第二个 .+ 匹配 f,符合正则 /(.+)(?!\.1)/.exec("123.141") 第一个 .+ 匹配到了 123.141 ,之后是 EOF 不是 .1,也符合正则 |
14
xiangyuecn OP @binux 嗯,原来如此呀,分解一下豁然开朗,哈哈
意思就是前瞻只能作用于+贪婪匹配到的最后一个字符,并不能阻止+对最后一个字符之前的所有字符进行贪婪匹配。 /(\d+)(?!\.1)/.exec("123.141") 目测是这样的: > 123:\d+贪婪匹配到.为止 > 12:发现 123.1 不符合(?!\.1),后退一位 > 没有表达式了,返回 12 /(.+)(?!\.1)/.exec("123.141") 目测是这样的: > 123.141:.+贪婪匹配到结尾 > 123.141 : 符合(?!\.1) > 没有表达式了,返回 123.141 /(.(?!\.1))+/.exec("123.141") 目测是这样的: > 1:.匹配到新的一位 > 1:123 符合(?!\.1) > 12:.匹配到新的一位 > 12:123.符合(?!\.1) > 123:.匹配到新的一位 > 12:发现 123.1 不符合(?!\.1),后退一位,并退出循环 > 没有表达式了,返回 12 如果要对每个字符进行前瞻检查,唯有最后一种写法比较好理解。 |
15
zhyl 2019-04-08 11:03:55 +08:00
试试这个 `<\w+(?!def)(?<!def)\b>`
|
16
xiangyuecn OP @zhyl 尽量不要用后瞻,难移植
|