
特意写了一篇文章记录了一下:
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 |
6 zhyl 2019-04-08 08:36:53 +08:00 via Android .+ 贪婪匹配 |
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 你这个非要用正则的话感觉只能 <(?!.+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 @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 尽量不要用后瞻,难移植 |