正则表达式 一个奇怪问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
faketemp
V2EX    问与答

正则表达式 一个奇怪问题

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

    测试工具: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。见 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
    div class="reply_content">又看了下那些回帖, 已经有答案了, 这个条件改用零宽断言是对的 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     Solana     947 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 19:44 PVG 03:44 LAX 12:44 JFK 15:44
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86