V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xiangyuecn
V2EX  ›  程序员

正则表达式 后面不要包含内容 的写法不生效?

  •  
  •   xiangyuecn ·
    xiangyuecn · 2019-04-08 08:09:39 +08:00 · 3226 次点击
    这是一个创建于 2041 天前的主题,其中的信息可能已经有所发展或是发生改变。

    昨天学会了如何编写 不要包含指定的字符串内容 的正则表达式写法。

    特意写了一篇文章记录了一下:

    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)不会生效,前瞻不会和前面的+、*、{}起作用吗?

    第 1 条附言  ·  2019-04-08 09:38:01 +08:00

    由于/<.+(?!def).+>/ 结尾还有一个贪婪匹配(虽然实际上只会匹配到结尾仅仅一个字符,看上去像是会匹配所有字符一样,不测试好难看出是哪个.+匹配出来的),这个例子不太好。

    换成#1楼这个例子吧,没这么多干扰:

    /<.+(?!def)zzz>/.exec("<abcdefzzz>\n<abczzz>")

    另注:这里所写的语法,js应该都支持的吧。

    xiangyuecn
        1
    xiangyuecn  
    OP
       2019-04-08 08:24:35 +08:00
    又发现另一种有效写法:
    /<(?!.+def).+>/.exec("<abcdefzzz>\n<abczzz>")

    可能是结尾的.+导致的不能匹配,但这样写还是不行:
    /<.+(?!def)zzz>/.exec("<abcdefzzz>\n<abczzz>")
    frank611
        2
    frank611  
       2019-04-08 08:26:55 +08:00 via Android
    def 后面的.+是不对的,+是必须匹配一个字符或者更多
    binux
        3
    binux  
       2019-04-08 08:27:32 +08:00
    /<(.+)(?!def)(.+)>/.exec("<abcdef>\n<abczzz>")
    你就知道为什么了
    xiangyuecn
        4
    xiangyuecn  
    OP
       2019-04-08 08:31:39 +08:00
    @binux 还是不明白,第一个分组捕获到 abcde,预期想要是 abc,前瞻不会和前面的+、*、{}起作用吗?
    binux
        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' 了吗
    zhyl
        6
    zhyl  
       2019-04-08 08:36:53 +08:00 via Android   ❤️ 1
    .+ 贪婪匹配
    labnotok
        7
    labnotok  
       2019-04-08 09:23:20 +08:00 via Android
    貌似 js 不支持预查吧,只能手动分组
    xiangyuecn
        8
    xiangyuecn  
    OP
       2019-04-08 09:27:46 +08:00
    @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")

    难以理解,最后一个就是我的写法,咳。。。
    araraloren
        9
    araraloren  
       2019-04-08 09:29:27 +08:00
    js 的正则有些特性不支持: https://www.regular-expressions.info/javascript.html
    xiangyuecn
        10
    xiangyuecn  
    OP
       2019-04-08 09:30:37 +08:00
    noqwerty
        11
    noqwerty  
       2019-04-08 09:37:16 +08:00   ❤️ 1
    你这个非要用正则的话感觉只能 <(?!.+def>).+> ,你的写法里 <.+(?!def).+> 第一个.+是贪婪的,会把 def 也包括进去。
    noqwerty
        12
    noqwerty  
       2019-04-08 09:38:06 +08:00
    另外测试正则的时候 https://regex101.com/ 很好用
    binux
        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,也符合正则
    xiangyuecn
        14
    xiangyuecn  
    OP
       2019-04-08 10:08:46 +08:00
    @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

    如果要对每个字符进行前瞻检查,唯有最后一种写法比较好理解。
    zhyl
        15
    zhyl  
       2019-04-08 11:03:55 +08:00
    试试这个 `<\w+(?!def)(?<!def)\b>`
    xiangyuecn
        16
    xiangyuecn  
    OP
       2019-04-08 11:05:53 +08:00
    @zhyl 尽量不要用后瞻,难移植
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1095 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 19:02 · PVG 03:02 · LAX 11:02 · JFK 14:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.