V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
faketemp
V2EX  ›  问与答

正则表达式 一个奇怪问题

  •  
  •   faketemp · 2019-10-21 22:30:21 +08:00 · 2031 次点击
    这是一个创建于 1620 天前的主题,其中的信息可能已经有所发展或是发生改变。

    测试工具:Notepad++
    测试文本: http://www.baidu.com,http://www.123.com,http://www.sina.com,MAIN
    测试正则: http.+?MAIN

    测试结果: http://www.baidu.com,http://www.123.com,http://www.sina.com,MAIN

    问题是非贪婪模式下最短匹配,结果不应该是“http://www.sina.com,MAIN”吗

    百思不得其解中……

    22 条回复    2019-10-22 11:57:59 +08:00
    faketemp
        1
    faketemp  
    OP
       2019-10-21 22:47:37 +08:00 via iPhone
    以前未遇到过这种奇怪问题 测试多个编辑器 结果都是一样 实在是费解
    shiji
        2
    shiji  
       2019-10-21 22:58:24 +08:00
    .+? 。*? 是 Lazy。
    懒惰的意思是,尽量少的匹配(不贪婪)直到满足条件。

    那么最前面的 http 是满足条件的,regex 里面的 http 也会相应的“划掉”,在到达终点 MAIN 之前,不管贪婪还是懒惰,中间的都得包含进去,没得选。

    (中途因为 http 已经匹配上了,再次看到 http 的时候 regex 会忽略,反正已经匹配了。)

    所以 Lazy 不能保证最短。。。
    faketemp
        3
    faketemp  
    OP
       2019-10-21 23:09:27 +08:00 via iPhone
    @shiji 看各种教程都说?符号是“最短匹配” 如果 lazy 不能保证最短 请问像上面需求如何才能匹配出所要的“最短匹配”结果呢(假设网址部分是不定长的)
    faketemp
        4
    faketemp  
    OP
       2019-10-21 23:17:00 +08:00 via iPhone
    @shiji 能够理解你的讲解 要查找出“最短匹配”结果 想到一种折中方案 就是先将文本逆序 正则匹配出结果后再逆序一次 😁这种方案好像很笨……
    lxk11153
        5
    lxk11153  
       2019-10-21 23:31:45 +08:00   ❤️ 1
    中间部分是.+?匹配中的。你可以试试断言来排除中间的 ht 河蟹 tp
    htt 河蟹 ps://blog.csdn.ne 河蟹 t/u01204 河蟹 7933/article/details/383 河蟹 65541
    shiji
        6
    shiji  
       2019-10-22 00:15:27 +08:00   ❤️ 1
    @faketemp 逆序其实不笨,并且很有效率。。

    设想这样一个字符串

    http://www.du.com,MAIN,http://www.123.com,http://www.sina.com,MAIN,http://www.baidu.com,MAIN,http://www.123.com,MAIN

    你期望的输出是什么?


    如果不逆过来, 试试
    ( http:((?<!MAIN|http).)*MAIN)

    然后跑代码找出最短的
    pkookp8
        7
    pkookp8  
       2019-10-22 00:29:29 +08:00 via Android   ❤️ 1
    因为正则都是从前向后的吧
    第一个 http 符合要求就开始匹配,然后才是.+?main 的最短
    lukaz
        8
    lukaz  
       2019-10-22 00:30:52 +08:00   ❤️ 1
    针对测试文本,假设网址部分不含逗号,那么可以这样: http[^,]+,MAIN
    faketemp
        9
    faketemp  
    OP
       2019-10-22 00:31:49 +08:00 via iPhone
    受以上指导启发 只能这样了 使用

    http((?!http).)+?MAIN
    或者
    http[^http]+?MAIN
    faketemp
        10
    faketemp  
    OP
       2019-10-22 00:33:19 +08:00 via iPhone
    @pkookp8 嗯 我甚至专门去查过 有什么正则支持逆序查找选项🤪
    lukaz
        11
    lukaz  
       2019-10-22 00:44:16 +08:00 via Android   ❤️ 1
    [^http]的意思不是想当然的[^( http)],不能这么用
    geelaw
        12
    geelaw  
       2019-10-22 04:17:26 +08:00 via iPhone   ❤️ 1
    Lazy 模式并不是 skip 模式。
    你的需求可以用一个 NFA 解决,基本思路是匹配 http,以及一坨不含 http 和 ,MAIN 的串,以及 ,MAIN。见 https://www.v2ex.com/t/602716
    faketemp
        13
    faketemp  
    OP
       2019-10-22 06:48:29 +08:00 via iPhone
    @lukaz 谢谢提示 深入测试一下确实如你所说 这种用法是不准确的
    所以目前来看 就只能使用零宽断言 http((?!http).)+?MAIN
    或者逆序后 lazy 模式查找

    @geelaw 理论能够理解 只是最终结果没看懂🤪
    noqwerty
        14
    noqwerty  
       2019-10-22 07:36:16 +08:00 via Android   ❤️ 1
    以前一直觉得自己写正则还可以,在 V2 看了几个帖子之后感觉自己真的菜
    toma77
        15
    toma77  
       2019-10-22 09:59:39 +08:00
    我最讨厌正则
    ClericPy
        16
    ClericPy  
       2019-10-22 11:14:32 +08:00
    昨天就看到这帖子, 然后...
    测试工具:Notepad++
    劝退了
    faketemp
        17
    faketemp  
    OP
       2019-10-22 11:21:07 +08:00
    @ClericPy 技术无关 zz

    师夷长技以制夷

    用 sublimetext 或者 emeditor 等测试 问题一样重现 个人习惯
    ClericPy
        18
    ClericPy  
       2019-10-22 11:23:01 +08:00
    @faketemp 太敏感了...
    本来以为是聊正则的, 结果... 这软件我没装, 不知道会是什么效果, 不来坑楼主
    ClericPy
        19
    ClericPy  
       2019-10-22 11:36:16 +08:00   ❤️ 1
    又看了下那些回帖, 已经有答案了, 这个条件改用零宽断言是对的 http(?:(?!http).)+?MAIN
    被测试工具四个字给误导了, 以为是上来问 notepad++ 软件问题

    提个小建议, 以后跨工具测试正则可以 https://regex101.com/ 省的一个个工具去安装了
    faketemp
        20
    faketemp  
    OP
       2019-10-22 11:45:49 +08:00
    @ClericPy 感谢关注

    目前收集到的几个正则 实测都可以准确查找
    分别为
    http(?:(?!http).)+?MAIN
    http:((?<!MAIN|http).)+?MAIN
    http((?!http).)+?MAIN

    记录一下给需要的 V 友学习哈
    ClericPy
        21
    ClericPy  
       2019-10-22 11:50:32 +08:00
    @faketemp
    呃, 这和 NFA 引擎不会做那些细致回溯有点关系, 可以参考用 aa 匹配 aaaa 会发现只会得到两个结果, 而不是三个结果, 基本上就是拿着正则串去原始字符串里找, 具体算法还挺有意思, 可以去了解下 NFA 和 DFA 方面的东西
    faketemp
        22
    faketemp  
    OP
       2019-10-22 11:57:59 +08:00
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3298 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 10:46 · PVG 18:46 · LAX 03:46 · JFK 06:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.